Get animation clip length using Animator?

I am working on a script that discreetly plays animation states, and that part is working. However I also need to get the length of the current clip but haven’t found a way to do it.

Here’s the code I’m using:

Animator anim = obj.GetComponent<Animator>();
if(anim != null) {
	anim.Play(track, -1);
	AnimatorStateInfo info = anim.GetCurrentAnimatorStateInfo(0);
	length = info.length;
	Debug.Log("Animation("+track+") :"+length);
	
	AnimationInfo[] clips = anim.GetCurrentAnimationClipState(0);
	Debug.Log("clips:"+clips.Length);
	foreach(AnimationInfo i in clips) {
		Debug.Log(i.clip.name+":"+i.clip.length);
	}
}

The animation is playing fine, but the length from AnimatorStateInfo is 0, and AnimationInfo count is 0, both of which are incorrect. My Animator controller has 3 states. I have also tried the ‘GetNext’ versions of these methods with the same results.

Anybody know how to get the length of the specified clip at runtime?

7 Answers

7

Using
UnityEditorInternal.AnimatorController
just work in Unity editor, for runtime
I do like this:


Animator anim = obj.GetComponent<Animator>();
float time;
RuntimeAnimatorController ac = anim[0].runtimeAnimatorController;	//Get Animator controller
    for(int i = 0; i<ac.animationClips.Length; i++)                 //For all animations
    {
        if(ac.animationClips[i].name == "AnimationName")            //If it has the same name as your clip
        {
            time = ac.animationClips[i].length;
        }
    }

Perfect man! It's just what i wanted!! Cheers!!

RuntimeAnimatorController ac = anim[0].runtimeAnimatorController; Why anim is table ([0]) ?

Thank you Felipe, I used this as a linq way. float time = anim.runtimeAnimatorController.animationClips.First(x => x.name == "AnimationName").length;

You da real MVP :D

Thank you, it worked +1

Exactly one year late to answer this question, so might be of little use now.

The current clip being played’s length can be read, in your case, using anim.GetCurrentAnimationClipState(0).length with one caveat - it has to be done in the next frame. Not much info on it but probably due to execution order of animation update.

I use a coroutine and wait for the end of frame. Just as an example:

IEnumerator ShowCurrentClipLength()
{
    yield return new WaitForEndOfFrame();
    print("current clip length = " + anim.GetCurrentAnimatorStateInfo(0).length);
}

thanks ... you help me :)

Length, not length :)

3 and a half years later, your answer is the best I found. The caveat you give is very important! WaitForEndOfFrame fixed my bug.

This was helpful, thanks

This works perfectly. This should be the best answer.

EDIT: Found it! Turns out that the Motion type is derived from AnimationClip, so all that’s required is a simple cast:

Animator anim = obj.GetComponent<Animator>();
if(anim != null) {
	UnityEditorInternal.AnimatorController ac = anim.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
	UnityEditorInternal.StateMachine sm = ac.GetLayer(0).stateMachine;
	
	for(int i = 0; i < sm.stateCount; i++) {
		UnityEditorInternal.State state = sm.GetState(i);
		if(state.uniqueName == track) {
			AnimationClip clip = state.GetMotion() as AnimationClip;
			if(clip != null) {
				length = clip.length;
			}
		}
	}
	Debug.Log("Animation:"+track+":"+length);
}

Note also that the UnityEditorInternal object cannot be used in runtime code outside of the editor, so there is still no way to my knowledge of obtaining the AnimationClip at runtime from an Animator state. More explained here: http://forum.unity3d.com/threads/242478-Reading-keyframe-curve-data-from-Animator

The way the abstraction/black boxing of the Animator/Mecanim system is set up is absolutely horrendous.

What if we want to set the length?

this will do the trick

Animator anim = GetComponent<Animator>();
float AnimationLength(string name) {
    float time = 0;
    RuntimeAnimatorController ac = anim.runtimeAnimatorController;   

    for (int i = 0; i < ac.animationClips.Length; i++)
        if (ac.animationClips[i].name == name)
            time = ac.animationClips[i].length;

    return time;
}

Fixed the code-formatting issue in the topic.

Animator animComp = GetComponent<Animator>();
animComp.GetCurrentAnimatorStateInfo(0).length;

AnimatorStateInfo documentation page:

Unity - Scripting API: AnimatorStateInfo

I added an extension to the Animator for this.

public static class AnimExtensions
{
	public static float ClipLength(this Animator anim, string clipName)
    {
		AnimationClip[] clips = anim.runtimeAnimatorController.animationClips;
		foreach(AnimationClip ac in clips) { if(ac.name == clipName) return ac.length; }
		return 0.0f;
    }
}

Note : Was having some issues with GetCurrentAnimatorStateInfo(0).length; and found out that animation may still show the original animation if you check during the Transition Duration