When you command an Animator Controller (such as changing its state or setting a parameter), it will not actually respond until the next time it gets updated and even then it might still not do what you want.
For example, if you call
Play then check which state is currently playing it will still return the previous state until the next frame and if you call
Play again during the same frame it will ignore each call after the first instead of ending up in the last state you told it to play:
// Currently Playing Idle. animator.Play("Jump"); var state = animator.GetCurrentAnimatorStateInfo(0); Debug.Log(state.IsName("Jump"));
This has several issues:
- It logs false because it's still Idle. It will only be playing the
Jumpanimation next frame.
- That means in order to wait for the animation to finish, we first have to wait a frame before we can find out its length.
- It assumes the
Jumpstate is on layer 0 (it usually will be, but assumptions like that will cause bugs in more complex systems).
- It is not possible to do something like
Debug.Log(state.name)to find out what the state actually is.
- That's a lot of text just to check what is playing.
// Assuming this happens in the same frame as the above. animator.Play("Attack"); state = animator.GetCurrentAnimatorStateInfo(0); Debug.Log(state.IsName("Attack"));
This has several more issues:
- It still logs false because it is still
- But this time it will not be playing the
Attackanimation next frame, nor the frame after that. All
Playcalls after the first are totally ignored, though it gives no error or other indication that this is happening.
- So in order to function reliably, the script needs to wait a frame, verify that the
Attackanimation is actually playing (and if not, play it and wait another frame and check again), then it can finally check how long that animation will actually take to play.
On the other hand, Animancer responds to commands immediately, can properly handle multiple commands in the same frame, and allows you to easily check any details you want:
AnimationClip jump, attack; // Currently Playing Idle. var jumpState = animancer.Play(jump); Debug.Log(animancer.States.Current == jumpState);// True. Debug.Log(animancer.IsPlaying(jump));// True. Debug.Log(jumpState.IsPlaying);// True. Debug.Log(jumpState.Clip.name);// The name of the AnimationClip. Debug.Log(jumpState.Length);// The length of the AnimationClip. var attackState = animancer.Play(attack); Debug.Log(animancer.IsPlaying(jump));// False (not jumping anymore). Debug.Log(jumpState.IsPlaying);// False (not jumping anymore). Debug.Log(animancer.IsPlaying(attack));// True. Debug.Log(attackState.IsPlaying);// True.
Note that you are also less likely to even need to know the animation length because Animancer has several easy ways of Waiting for Animations to End.
This video shows the character from Unity's 3D Game Kit appearing to float up into the air instead of playing the jump animation. The script checks if it is grounded to make sure it can jump, then tells the Animator Controller that it's not
Grounded anymore (you can see the parameter change) and starts moving them into the air. But the Animator Controller has its own separate set of rules to determine when to go to the jumping animation, which prevents it from doing what the script already made sure the character should be able to do.
If Unity themselves can't even use their own system reliably, how can anyone else be expected to?