Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Wait for animation to end inside a State Machine

Discussion in 'Scripting' started by dichtermut, Jul 27, 2022.

  1. dichtermut

    dichtermut

    Joined:
    Jul 21, 2018
    Posts:
    26
    I am implementing a state machine for an AI Enemy and one of the states involves just staying idle for some frames while an animation is rendered. I want to advance to the next state once the animation has ended, but I am not sure how to do it. Generally, I would add an event on the last frame of the animation to call the method, but the method to call is:

    Code (CSharp):
    1. public void ChangeState(BaseState newState) {
    2.         currentState.Exit();
    3.         currentState = newState;
    4.         currentState.Enter(allCellsList);
    5. }
    And here I have the problem that it doesn't seem possible to pass an instance of my self-defined Type BaseState from the Animation window in Unity. I could make an auxiliary method to call with an integer or something to represent the new state to change to, but that seems wrong.

    So I was wondering, is there a more elegant way to do it?
    - Would it be a good idea to start a coroutine to wait for the X frames until the animation ended, and then just called ChangeState() to the next one? I'm guessing that State Machines and Coroutines don't mix very well together, plus, it doesn't seem right to invoke a coroutine for X frames every time I want an animation to render.
    - Would it be a good idea to just delete the state and add the animation at the end of the previous one? But then again, I would still have the problem of how to wait for the animation to end...

    Just as information, the state machine I implemented has four methods per state:
    1. Enter()
    2. UpdateLogic()
    3. UpdatePhysics()
    4. Exit()
     
  2. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    551
    I usually handle this logic directly in the specific state, so the state "detects" when the animation is done and triggers the state change to the next change

    I used different ways to "detect" the end of the animation, the old way was to use custom animator state behavior which invokes a custom C# event AnimationDone with the animation Id parameter, the state could then listen to the C# event of the custom component and then trigger the change to the next state.

    It worked fine but was to annoying to add the behavior / event to every animator / animation, so I just put the logic directly inside the state and detect the animation end with a combination of https://docs.unity3d.com/ScriptReference/Animator.GetNextAnimatorStateInfo.html and https://docs.unity3d.com/ScriptReference/Animator.GetCurrentAnimatorStateInfo.html

    It's only a few line of code and works for the most simple cases. I only use the animation behavior for complex animations with have multiple transitions etc and not just one simple animation, but even then I tend to convert more towards Timelines for these "complex" animations.

    Some additional hints:
    When you trigger a animation state change the GetCurrentAnimatorStateInfo will not immediately return the new state, because there is usually a 1 frame delay + additional delay for transitions, but you can use GetNextAnimatorStateInfo which returns the info of the next state during the transition.

    In the most basic case you could just check GetCurrentAnimatorStateInfo in every state update until your animation is started, set a flag somewhere in your state and then wait until the GetCurrentAnimatorStateInfo is not your specific animation anymore.

    But I also use GetNextAnimatorStateInfo to detect more "complex" cases, so it depends on your animator setup.
     
    Last edited: Jul 27, 2022
  3. arthurramoscreative

    arthurramoscreative

    Joined:
    Sep 13, 2020
    Posts:
    1

    Maybe it's a noob question but, how do I get the Animator (this instance specifically) via script once it's a state machine script, and I can't just use:
    "anim = gameObject.GetComponent<Animator>();"
    ?
     
    Last edited: Mar 14, 2024