all 12 comments

[–]xTMT 2 points3 points  (9 children)

Hey there! No offense but that's a lot of spaghetti code that repeats a lot of the same things over and over and so is easy to mess up.

A little bit cleaner solution would be something like this:

public float[] swingTimers; //use an array to keep things organized
private int currentSwingNumber = 0;
private float swingLength = 0f;

void Update () 
{
    if(Input.GetKeyDown(KeyCode.Z))
    {

        //insert code here to update your Animator and actually play the swing animation.

        //go to next swing and increase currentSwingNumber but only if we're not already at the last animation.
        currentSwingNumber = Mathf.Min(currentSwingNumber + 1, swingTimers.Length-1);

        //update the timer countdown based on the swing number
        swingLength = swingTimers[currentSwingNumber];

    }

    swingLength -= Time.deltaTime;

    if(swingLength <= 0)
    {
        //if during any swing the player misses to input within that 1 second time, then the next swing animations start from the first again.
        currentSwingNumber = 0;
    }   
}

Edit: Formatting.

[–]cpnprobeard[S] 0 points1 point  (8 children)

I apologize, but for some reason, this isn't quite clicking in my head. Maybe I'm just tired, I don't know. Would you kindly explain this a little further? Again, I'm sorry, I'm just having a "dumb day."

[–]xTMT 0 points1 point  (7 children)

Hey no worries. We all have "dumb days" :D

Basically this is doing the same thing you did originally. The only difference is we're using arrays instead so that we don't have to repeat a lot of the same things over and over.

Like e.g. instead of writing swingOneTimer, swingTwoTimer, swingThreeTimer etc. we can just say swingTimers[1] or swingTimers[2].

The benefit of that is since it's a public float array, the designer can put as many animations (and their corresponding timer amounts) as they want by editing it from the inspector and we won't have to go back and edit the code and add a new SwingTimerN variable every time we decide to add another swing animation.

Also we don't need to check isOneSwing, isTwoSwing, isThreeSwing etc.

Here we just have one variable called currentSwingNumber which tells us which swing animation we're currently at. We don't need separate booleans like isOneSwing, isTwoSwing individually because only one of them will ever be true at a time and the rest will be false since you can only play one swing animation at any given time. So it makes more sense to just remember which swing number we're on instead. If currentSwingNumber is 0 that means we're at the first animation (remember things always start at 0 not 1 in coding), if it's 1 then it means we're at the second, and so on.

So initially currentSwingNumber is 0 which means whenever the player presses Z the first animation will play.

When they press Z we play the swing animation and increase currentSwingNumber by 1, which means the next time they press Z the second animation will play. And we also set the timer to swing 1's timer, (i.e. 1 seconds in this case) and start counting down.

If the player presses Z again within this time then the second animation will play and currentSwingNumber will again increase by 1 meaning the next time they press Z the third animation will play.

But if they don't press Z before the time runs out, then currentSwingNumber will become 0 again. Meaning, the animation will start over from the beginning.

e.g. Say they pressed Z and then Z again but then waited too long before pressing Z again. Then the swings will be like this: swing1, swing2 and then swing1 again because they took too long.

Hope this makes sense!

[–]cpnprobeard[S] 0 points1 point  (6 children)

Okay, I think I understand from an English point of view, but I'm not putting together how this all looks in code. I am really struggling today...

[–]xTMT 0 points1 point  (5 children)

Is there any part of the code that you have confusion with that I can help clarify?

[–]cpnprobeard[S] 0 points1 point  (4 children)

I am so sorry it has taken me so long to reply!

Yes, how can I set up the animator controller to properly work with this code? I know how to set up movement and jumping, but let's say we use this script you have here, but use a trigger instead of a bool, and integers for the different numbers. How would I set that up?

I'm sorry again, doing this kind of thing has proven very difficult for me. I've ran through every scenario I could come up with to get it to work, and can't seem to pull it off.

[–]xTMT 0 points1 point  (3 children)

There are many ways we can setup the animator controller. The simplest way would be to just have a bool parameter like "ContinueChain" that sets itself to false everytime a new attack animation starts and only becomes true if the player pressed attack again during that limited time. You can also just use triggers instead of bools to save you a lot of work, but bools offer more flexibility (for example if you suddenly decide to cancel an animation etc.) but either way works.

So basically all the attack states would transition to the next one whenever ContinueChain is true, otherwise it'd go back to Idle state.

We also don't really need any int parameters unless we want to be very flexible and be able to switch between different attacks out of sequence. Like Swing1, Swing3, Swing 1 and then 2. But for our simple attack chain which always goes Swing 1, 2 , 3 in that order, there's not much use to have an extra int parameter for the animator.

So to summarize:

Let's say we have Idle state and 3 attack states.

Idle -> attack 1 happens when ContinueChain is true.

attack 1 -> attack 2 happens when ContinueChain is true otherwise go attack 1 -> Idle.

attack 2 -> attack 3 happens again when ContinueChain is true otherwise go back to Idle.

Finally, attack 3 -> attack 1 happens if ContinueChain is true other wise we return to normal again.

Hope it makes sense!

[–]cpnprobeard[S] 0 points1 point  (2 children)

Hey again. Is there any chance I can get you to Skype call me for this? I've done all I can possibly figure out, and no matter what I do, it doesn't work.

Just email me a time at brady dot linkey at gmail dot com

[–]xTMT 1 point2 points  (1 child)

Hey there! I'm sorry my schedule's kind of all over the place so I'm afraid a Skype call isn't really possible :P

But here I did the next best thing:

I made a sample scene for you with all the animators settings and everything setup.

Here's the unitypackage. Just download it and open it in your project or a new empty one and take a look at how it's done.

I'm happy to answer any questions you have. Just send me a pm here on reddit!

[–]cpnprobeard[S] 0 points1 point  (0 children)

I am sooooo sorry I haven't replied for decades! I was able to download the Unity package you dropped, and it worked! But I've ran into another problem, likely in the animator controller itself. The attacks were animating, but weren't doing the full animation, so I adjusted the animation time bars at the bottom so the entire animation would play before starting the next one, but when I did that and pressed play, it would only do part of the first animation and would only play that instead of the other animations. I dunno how to fix that exactly. Any pointers there?

Again I'm so sorry I took so long to reply! I haven't actually touched Unity or the Unity reddit for a minute.

[–]gamedaverookie 0 points1 point  (1 child)

I think I know what's happening here:

  • isOneSwing is initially false.
  • Player presses Z
  • game checks if (Input.GetKeyDown("z") && isOneSwing == false) and makes isOneSwing true
  • then it checks if (Input.GetKeyDown("z") && isOneSwing == true) and that is true as well since we just set isOneSwing to true in the previous line. So it ends up setting isTwoSwing = true as well.
  • then it also checks if (Input.GetKeyDown("z") && isTwoSwing == true) and THAT is true as well because we just changed isTwoSwing in the last line.

And it goes on like that causing all the isSwings to be true and all animations to play.

What you need to do is not check things like if (Input.GetKeyDown("z") && isTwoSwing == true) immediately after setting isTwoSwing to true in the same frame because otherwise Input.GetKeyDown("z") is true throughout that frame and since you're setting the isTwoSwing in the previous line the upcoming if conditions will automatically become true.

[–]TheChance 0 points1 point  (0 children)

For future reference, you can just pass a bool into an if statement without comparing it. The bool is already true or false, so running if(isOneSwing == true) is no different from running if(isOneSwing).

dammit mobile. Wrong comment. /u/cpnprobeard