- Home /
How can i use the Animator in script to find when animation clip finished playing and then stopping the animation ?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimationCamera : MonoBehaviour
{
public Camera animationCamera;
public Camera mainCamera;
Animator _anim;
AnimatorStateInfo currInfo;
float animationnormalizedTime;
private void Start()
{
animationCamera.enabled = false;
mainCamera.enabled = true;
_anim = GetComponent<Animator>();
currInfo = _anim.GetCurrentAnimatorStateInfo(0);
animationnormalizedTime = currInfo.normalizedTime;
}
private void Update()
{
if (currInfo.length == animationnormalizedTime)
{
_anim.CrossFade("Animation_Idle", 0);
}
if (Input.GetKeyDown(KeyCode.C))
{
animationCamera.enabled = !animationCamera.enabled;
mainCamera.enabled = !mainCamera.enabled;
if (animationCamera.enabled)
{
_anim.CrossFade("Animation_Sign", 0);
}
else
{
_anim.CrossFade("Animation_Idle", 0);
}
}
}
public void PlaySignAnimation()
{
animationCamera.enabled = true;
_anim.CrossFade("Animation_Sign", 0);
}
}
I'm trying to use the currInfo. I want to find the animation clip length and also how much time currently passed since the animation clip started. Then to compare the values and in the end to make it "Animation_Idle".
Sub question: "Animation_Idle" is a state i created in the Animator window so it will not play anything. But maybe it's the wrong way to stop animation using Animator. Should i use something else to stop the animation instead using "Animation_Idle" ?
First You should use the transitions between an animation clips in Animator editor. So you dont need to check if animation ends.
When you make transition (arrow) between the 'sign' and the 'idle' it will be enough. Next make sure the 'sign' clip is not looped simply click on clip in Project and uncheck 'Loop Time' . Now when you run 'sing' animation (with animator.Play("animation_sign");) it will automatically skip to the 'idle' animation when it ends.
Ok i did it and it's playing it once now. But then in the end it's not getting back to the $$anonymous$$ain Camera. I did in the script enable true to the animationCamera in the PlaySignAnimation method:
animationCamera.enabled = true;
So now when it finish playing the clip i'm getting this in the game view: It's not the main camera and not the animationcamera. Somehow i need in the script to make that when it finish playing the animation clip change the animationcamera enable to false and make the main camera enable to true.
I checked the Animator window. It start when the game start on idle then it get to the animation clip state when finish it back to the idle state. The problem is that nothing tell the cameras to do the switch back when it finish playing.
Click the 'AddBehaviour' button on Animator->'Animation_Sign' it will be placed in inspector. Then open created script and attach this code:
private AnimationCamera _animCamera; // handler
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if(_animCamera == null)
{
_animCamera = animator.GetComponent<AnimationCamera>();
}
if(_animCamera != null)
{
_animCamera.RunCameraDetach$$anonymous$$ethod();
}
}
It requires add to your class public method to execute when animation ends. it will works if AnimationCamera is placed on the game object with the Animator component.
You can read about state machine behaviours on: https://unity3d.com/learn/tutorials/modules/beginner/5-pre-order-beta/state-machine-behaviours
Answer by FM-Productions · May 08, 2017 at 06:03 PM
Hi,
I think your script is already on the right path, but none the less, I try to give a complete answer to the question below. If you have a transition "On Exit Time" set from your current state, you could simply check when the current animation state name is not your previous animation anymore. Else you can work with the normalizedTime, like you already do in your script.
You can get the current state info with Animator.GetCurrentAnimatorStateInfo
. If called with a parameter 0, you should get the currently active animation state: animator.GetCurrentAnimatorStateInfo(0)
where animator
is the variable that stores your Animator. You can then proceed to check the animation you are in, for example by comparing the name of the current animation:
if (animator.GetCurrentAnimatorStateInfo(0).IsName("Animation_Idle")){ }
You can get the time of the current state via the normalizedTime
, this is a float value between 0 and 1 where as 0 is the very start of the animation and 1 is the end of the animation. Think of it as how many percent of the animation has been played. for example a normalizedTime of 0.34 means that 34% of the animation has been played. Without testing it, but after looking in the Unity docs, I think you can access the normalizedTime of the current animation like this.
animator.GetCurrentAnimatorStateInfo(0).normalizedTime
Something I noticed about your script, at line 26: Do not do this:
if (currInfo.length == animationnormalizedTime)
Instead, check if the value is above a threshold instead of an exact value. Also, let's say you want to switch from "Animation_Idle" to another state, do this instead (you don't want to call your animation switch function in every animation state or do you?). Also, forget currInfo.length
, set the normalizedTime, when you want to exit as a separate variable.
if (currInfo.IsName("Animation_Idle") && currInfo.normalizedTime >= customSetNormalizedTime)
The last thing is, I think you have to call currInfo = _anim.GetCurrentAnimatorStateInfo(0);
in your Update() function, not the start function. Else I believe you will have the same currInfo in every update (the currInfo you got in the Start() function), but you want to have the currInfo of the current frame.
However, for switching between animation states, I think setting up transitions in the Animator itself is preferable to control everything from script. Then maybe set variables in your animator and transition conditions for animation states that depend on the variable values. You can then communicate with the Animator in the script. If you are trying to learn Unity's animation system or if it still feels unfarmiliar to you, and if you have the time, maýbe check out this video:
https://www.youtube.com/watch?v=wdOk5QXYC6Y
Also, if you don't know how to get a certain value from the Animator or other classes, make sure you check the API docs first, since they describe every possible function and method you can call on certain Unity classes:
https://docs.unity3d.com/ScriptReference/Animator.html
If hope I could help you!
i've tried to get 'normalized time' from an animation but it does not go from 0 to 1, it keeps counting up (indefinitely as far as i know)
That's why you check if normalizedTime is >= 1. normalizedTime doesn't stop "counting" when animation has finished playing, because if you had a loop you could know how many times the animation played.