How can I check if an animation is playing or has finished? (Using Animator/C#)

I’m using the animator component to animate my character in my game and C# to code it, and I want the game to know if an animation is playing or has finished, because they are a lot of things I intend to code into the game that would require knowing if an animation is playing of finished.

I’ve looked it up, and the only solutions I’ve found were in Javascript and for the Animation component.

If it helps, I’ll put my situation in, my character pulls out a gun, I want the game to know that while it does that, the player cannot shoot, reload or change weapons until that animation is finished, how would I do that?

I’m talking about the “Animator” component, not “Animation”.

If you use the animator and mecanim, then I think you should do something like that :

if (this.animator.GetCurrentAnimatorStateInfo(0).IsName("YourAnimationName"))
{
   // Avoid any reload.
}

Be aware that your animation name should be similar to “Layer_Name”.“State_Name” but if you use a “sub-state machine” in mechanim then the animation name must be “Sub-StateMachine_Name”.“State_Name”.

I hope it may help you!

Cheers,
Flo

I check it with the time … after i switch to another animation (like with a trigger) i have following condition:

if (Animator.GetCurrentAnimatorStateInfo(0).normalizedTime > 1 && !Animator.IsInTransition(0))

works like a charm for me

the check for animator is in transition check is mandatory cause otherwise there will be for 1 or 2 frames the time of the last state
unity resets the time after the transition is completed

To know if Animator is playing any animation:

 bool AnimatorIsPlaying(){
    return animator.GetCurrentAnimatorStateInfo(0).length >
           animator.GetCurrentAnimatorStateInfo(0).normalizedTime;
 }

To know if is playing a specific animation:

 bool AnimatorIsPlaying(string stateName){
    return AnimatorIsPlaying() && animator.GetCurrentAnimatorStateInfo(0).IsName(stateName);
 }

I cannot add some code in the comment space, so I have answered there… sorry…

There is no “StateEnded” or “TransitionEnded” event for now on the mecanim system…
So the only way to do that is to pull the “CurrentAnimatorStateInfo” and check if you enter the state/leave it.

if(this.animator.GetCurrentAnimatorStateInfo(0).IsName("YourAnimationName"))
  {
      // Avoid any reload.
      this.InMyState = true;
  }
  else if (this.InMyState)
  {
       this.InMyState = false;
       // You have just leaved your state!
  }

The number is the layer index. Basically, if you have not created a new layer in your mecanim window, you only have one layer at index 0.

Hello, I had this same sort of problem recently. Basically I had a phone object with an animator containing logic and animation clips for “PowerOff” and “PowerOn”. The goal was to play either of the animations, only under the condition that the other has finished playing.

When playing an animation I set a local bool allowTogglePower to false. To detect the end of the animation I used an AnimationEvent through the animation editor attaching a function which sets allowTogglePower to true.

Something like:

public class PhoneEx : MonoBehaviour
{
    public Animator anim;
    bool allowTogglePower = true;
        
    // Called by UI Button Input
    public void ToggleAnimation() 
    {
        if(anim.GetBool("PowerOn") && allowTogglePower)
        {
            anim.SetBool("PowerOn", false);  // Plays OffAnim
            allowTogglePower = false;
        }
        else if(allowTogglePower)
        {
            anim.SetBool("PowerOn", true);   // Plays OnAnim
            allowTogglePower = false;
        }
    }
    
    // Called by AnimationEvent on last frame of each animation
    public void SetToggleOk()
    {
        allowTogglePower = true;
    }
}

It is worth noting that I also set anim.enabled to false in SetToggleOk(). I then set it back to true when playing an animation… Might not be practical for big animator systems, but I don’t like how the animator iterates through the frames of an animation, even though it has finished and looping is turned off.
,

@alok-kr-029 i just simply your solution.

just send your animation name in CurrentAnimation you want to check.

 public IEnumerator CheckAnimationCompleted(string CurrentAnim, Action Oncomplete)
    {
        while (!Animator.GetCurrentAnimatorStateInfo(0).IsName(CurrentAnim))
            yield return null;
        if (Oncomplete != null)
            Oncomplete();
    }

calling coroutine

 StartCoroutine(CheckAnimationCompleted("Shoot", () =>
         {
             Animator.SetBool("Shoot", false);
             // Your any code
         }
        ));

Its old post But I found a better solution

public static IEnumerator CheckAnimationCompleted(string toPlayAnim, string endAnim, Action Oncomplete)
    {
        LevelManager.instance.playerAnimRef.animCntroller.SetTrigger(toPlayAnim);
        while (LevelManager.instance.playerAnimRef.animCntroller.GetCurrentAnimatorStateInfo(0).IsName(endAnim))
            yield return null;

        while (!LevelManager.instance.playerAnimRef.animCntroller.GetCurrentAnimatorStateInfo(0).IsName(endAnim))
            yield return null;

        if (Oncomplete != null)
            Oncomplete();
    }

How To call the function

StartCoroutine(
Utilities.CheckAnimationCompleted(“PickObject”, “Idle”, () =>
{ playerRef.CanTakePlayerInput = true; } ));

The following code will help you.
The method returns true if the playing of an animation state on animator is still playing.,
otherwise returns false.
If the layer is “Base Layer” in the Animator View, you should use 0 for the animLayer.

bool isAnimationStatePlaying(Animator anim, int animLayer, string stateName)
{
    if (anim.GetCurrentAnimatorStateInfo(animLayer).IsName(stateName) &&
            anim.GetCurrentAnimatorStateInfo(animLayer).normalizedTime < 1.0f)
        return true;
    else
        return false;
}

// to check if an animation has finished playing

Animator anim;

void Start () {
anim = GetComponent();
}

void Update () {

if (anim.GetCurrentAnimatorStateInfo (0).length < anim.GetCurrentAnimatorStateInfo(0).normalizedTime) {
Debug.Log (“animation has finished!!”);}

I have tried using:

this.animator.GetCurrentAnimatorStateInfo(0).IsName("YourAnimationName")

Unfortunately, it’s not working for me. Because it’s always True. Maybe it’s caused by my animator setting as the picture.
90409-screenshot01355.png

However, I figure out another way(by checking its elapsed time and overall duration) and working. Here it is:

		var animDuration = animator.GetCurrentAnimatorStateInfo(0).length;
		var elapsedTime = animator.GetCurrentAnimatorStateInfo(0).normalizedTime;
		var bFinished = (elapsedTime > animDuration/2f);

If you do not have any transitions and would like to to be notified when the animation has ended for the “stateName” in layer 0, I did by calling the following IEnumerator :

   public IEnumerator PlayAndWaitForAnim(Animator targetAnim, string stateName)
    {
        targetAnim.Play(stateName);

        //Wait until we enter the current state
        while (!targetAnim.GetCurrentAnimatorStateInfo(0).IsName(stateName))
        {
            yield return null;
        }

        //Now, Wait until the current state is done playing
        while ((targetAnim.GetCurrentAnimatorStateInfo(0).normalizedTime) % 1 < 0.99f)
        {
            yield return null;
        }

        //Done playing. Do something below!
        EndStepEvent();
    }

The main logic is once the state is entered, we should check if the fractional part of ‘normalizedTime’ variable reached 1, which means the animation has reached its end state.

Hope this helps

My solution. It plays “attack” animation, then returns to default “stand”.

(“stand” is looped, “attack” is not. no state triggers used)

if (Input.GetMouseButtonDown(1))
        {
            an.Play("Base.pl1-atk");
        }
        if (an.GetCurrentAnimatorStateInfo(0).IsName("Base.pl1-atk"))
        {           
            if (an.GetCurrentAnimatorStateInfo(0).normalizedTime > 1)
            {
                an.Play("Base.pl1-stand");
            }
        }