Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We are updating our Terms of Service for all Unity subscription plans, effective October 13, 2022, to create a more streamlined, user-friendly set of terms. Please review them here: unity.com/legal/terms-of-service.
    Dismiss Notice
  3. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    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:
    1
    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:
    506
    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
unityunity