Search Unity

How can I detect when animation play has finished and then do something ?

Discussion in 'Scripting' started by Chocolade, Jan 27, 2020.

  1. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    933
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class PlayAnimation : MonoBehaviour
    7. {
    8.     private Animator anim;
    9.     private bool started = true;
    10.  
    11.     // Start is called before the first frame update
    12.     void Start()
    13.     {
    14.         anim = GetComponent<Animator>();
    15.     }
    16.  
    17.     private void Update()
    18.     {
    19.         if (Whilefun.FPEKit.FPESaveLoadManager.gameStarted == true && started == true)
    20.         {
    21.             anim.enabled = true;
    22.             anim.Play("Stand Up", 0, 0);
    23.             started = false;
    24.         }
    25.     }
    26. }
    27.  
    I want that when "Stand Up" finished playing to do something.
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I believe you can edit your animator states or transitions (I forget which; possibly both) to have events, causing them to call specific functions in your code when they reach a particular point.
     
    Chocolade likes this.
  3. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    933
    I tried this now :

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class PlayAnimation : MonoBehaviour
    7. {
    8.     private Animator anim;
    9.     private bool started = true;
    10.     private float standupTime = 0;
    11.  
    12.     // Start is called before the first frame update
    13.     void Start()
    14.     {
    15.         anim = GetComponent<Animator>();  
    16.     }
    17.  
    18.     private void Update()
    19.     {
    20.         if (Whilefun.FPEKit.FPESaveLoadManager.gameStarted == true && started == true)
    21.         {
    22.             anim.enabled = true;
    23.             anim.Play("Stand Up", 0, 0);
    24.             GetAnimationsLength();
    25.             StartCoroutine(StandUp());
    26.             started = false;
    27.         }
    28.     }
    29.  
    30.     private IEnumerator StandUp()
    31.     {
    32.         yield return new WaitForSeconds(standupTime);
    33.  
    34.         Debug.Log("Animation has finished after : " + standupTime + " Seconds");
    35.     }
    36.  
    37.     private void GetAnimationsLength()
    38.     {
    39.         AnimationClip[] clips = anim.runtimeAnimatorController.animationClips;
    40.  
    41.         foreach (AnimationClip clip in clips)
    42.         {
    43.             switch (clip.name)
    44.             {
    45.                 case "Stand Up":
    46.                     standupTime = clip.length;
    47.                     break;
    48.             }
    49.         }
    50.     }
    51. }
    52.  
    I used a break point now and the animation clip in this case length is about 8 seconds.

    But when it's getting to the Debug.Log line it's after 3-4 seconds not 8 when I make Continue it's continuing the animation. It's like it's getting to the Debug.Log line after 4 seconds in the middle not when the animation finished playing.

    And second I don't see the Debug.Log i the console.
     
  4. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,317
    You can create StateMachineBehaviour classes and attach them to states in the state machine. These classes have a callback for when mechanim leaves the state. @Chocolade you can add your code there.
     
    Chocolade likes this.
  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I've tried to write code that synchronizes with animations by waiting the length of the animation clip, and I found it tends to be inaccurate because of blending and other complexities that may delay or blur the start or end of an animation. I recommend you switch to events instead.

    Also, note that your GetAnimationsLength function isn't actually checking the current clip, it's looking at all defined clips, so if you ever care about more than one clip it won't work anymore.
     
    Chocolade likes this.
  6. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    933
    Using unity 2019.2.5f1 Personal.

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class PlayAnimation : MonoBehaviour
    7. {
    8.    private Animator anim;
    9.    private bool started = true;
    10.  
    11.    // Start is called before the first frame update
    12.    void Start()
    13.    {
    14.        anim = GetComponent<Animator>();
    15.    }
    16.  
    17.    private void Update()
    18.    {
    19.        if (Whilefun.FPEKit.FPESaveLoadManager.gameStarted == true && started == true)
    20.        {
    21.            anim.enabled = true;
    22.            anim.Play("Stand Up", 0, 0);
    23.            started = false;
    24.        }
    25.    }
    26. }
    27.  
    I want to know when playing the "Stand Up" state has finished and do something else. In this my character(player) is standing up when using this animation "Stand Up" and I want to detect when the player has finished standing up and then do something.

    I tried to use event but it's getting to the Debug.Log when the animation start playing not finished :

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class SMachineBehaviour : StateMachineBehaviour
    7. {
    8.    public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    9.    {
    10.        Debug.Log("State EXited");
    11.    }
    12. }
    13.  
    This script is attached to the state Stand Up but using a break point it's getting to the Debug.Log when the animation start playing and not when finished playing.