Search Unity

Wait for the end of an animation

Discussion in 'Animation' started by Kr0e90, Jun 11, 2014.

  1. Kr0e90

    Kr0e90

    Joined:
    Nov 25, 2012
    Posts:
    6
    Hi,

    I'm developing a 2d game heavily using the "new" animation system (Animator Controller -> not legacy).

    While the whole animator stuff is really helpful in some situations, it really misses one key feature for advanced scripting (or maybe I' wrong?):

    How can you wait for an animation to finish via scripting ?

    There are a couple of ways I could think of but which do not work in my situation:
    - Put the animation as a class attribute via editor into the script (Bad, because no loose coupling)
    - Put the length of the animation in the class via editor and do coroutine waiting (Bad, because time varies between animations)
    - Use GetCurrentAnimationState (Bad, because a) after you played an animation using Animator.Play() the current animation state might be unchanged four a couple of frames, b) if the animation is really short, the script might not notice the change and stalls forever)

    ----> Why the hell does Animator not expose an array of all animations ? This way I could simply get the length of an animation, play the animation while waiting via coroutines and continue...

    Why is the old system legacy while the new does allow fewer features ? You cant reduce features and call this improvements.

    So please, am I totally wrong and miss something or do i really need one of those upper 3 (bad) options ?

    Thanks in advance!
    Chris
     
  2. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,694
    Mecanim just has a different approach, but with 4.3+ you can do almost everything that you could do in Legacy (and of course much more).

    What about adding an animation event?

    BTW, Animator.GetCurrentAnimationClipState() returns an array of AnimationInfo[], which is a struct of AnimationClips and weight. So you can get the array of animations for the current state. But if I were to go this route I would use Animator.GetCurrentAnimatorStateInfo(). As soon as you change states (as long as it's a different state), you're guaranteed that it will return different info, so your coroutine knows to stop.
     
    Last edited: Jun 11, 2014
  3. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    Hi Chris,

    Like TonyLi said, the best way to handle this is with AnimationEvent. Simply add an AnimationEvent at the end of your clip, this event will call a predefine function that you will provide when the clip finish to play.

    In the next release of Unity 5.0 you will have another way to handle this with a script that you will put on your state
    This new feature is called StateMachineBehavior. which can handle a few predefine callback message

    StateMachineBehaviour.OnStateEnter()
    StateMachineBehaviour.OnStateExit()
    StateMachineBehaviour.OnStateUpdate()
    StateMachineBehaviour.OnAnimatorMove()
    StateMachineBehaviour.OnAnimatorIK()
     
    rrh likes this.
  4. Kr0e90

    Kr0e90

    Joined:
    Nov 25, 2012
    Posts:
    6
    Thanks guys! Very good to know that unity5 will help! I can't wait for it, not just because the animation stuff ;)

    Well I guess I'll try the StateInfo route again, AnimationEvents are nice but I want to trigger with my script arbitrary animations from different GameObjects in one Script.

    For more context:

    I doing one of those old pixel style games (ala Monkey Island or Indiana Jones) and I'm working on a conversation script between two people.

    The script gets an array of strings which start either with
    A:<text from A> or
    B:<text from B> or
    #A:<animation name of A>
    #B:<animation name of B>

    So I can use the same script and just change text and animation names. But, of course, I have to know when the triggered animation has completed so the conversation can go on...

    But I don't actually want the animations to be aware of this script so AnimationEvents wont fit in this scenario..

    But again thank!

    Cheers,
    Chris
     
  5. Kr0e90

    Kr0e90

    Joined:
    Nov 25, 2012
    Posts:
    6
    So, tested it again, and it GetCurrentAnimationStateInfo() does return a different state after changing:

    var currentAnimator = partner.GetComponent<Animator> ();
    currentAnimator.Play (StateName);
    Debug.Log (currentAnimator.GetCurrentAnimatorStateInfo (0).IsName(StateName)); // False!!

    So the state does not change immediately. When I add a yield return new WaitForFixedUpdate() or something like that the state is correct. But I would trust this behavior, so I'm pretty much out of luck here I guess...
     
  6. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    It is expected in this case, when you call Animator.Play, the animator must be ticked by the game engine first before you will see any change.
     
  7. Kr0e90

    Kr0e90

    Joined:
    Nov 25, 2012
    Posts:
    6
    So it can be considered "safe" to wait for fixed update and then poll the state ?
     
  8. JohnnyA

    JohnnyA

    Joined:
    Apr 9, 2010
    Posts:
    5,041
  9. Kr0e90

    Kr0e90

    Joined:
    Nov 25, 2012
    Posts:
    6
  10. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    You should do it in the LateUpdate, this way you are sure that everything else has been evaluted