End Events | Exit Events |
---|---|
When an animation time reaches its end. | When an animation is interrupted. |
After you start an animation, you will often want to wait for it to finish before doing something else so Animancer has several different ways to do that:
|
The |
End Events are available in Animancer Lite, but the ability to set a custom end time is Pro-Only so you can try it out in the Unity Editor but it will not be available in runtime builds unless you purchase Animancer Pro. |
Pro-Only: Animancer Lite allows you to try out Exit Events in the Unity Editor, but they will not be available in runtime builds unless you purchase Animancer Pro. |
Events
The Animancer Event system allows you to run script functions at certain times throughout an animation. Each AnimancerEvent.Sequence
also has an EndEvent
which works a bit differently from other events in order to be more useful for defining the end of the animation:
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private AnimationClip _Animation;
void PlayAnimation()
{
var state = _Animancer.Play(_Animation);
state.Events.OnEnd = OnAnimationEnd;
state.Events.NormalizedEndTime = 0.75f;
// Or set the time and callback at the same time:
state.Events.EndEvent = new AnimancerEvent(0.75f, OnAnimationEnd);
}
void OnAnimationEnd()
{
Debug.Log(AnimancerEvent.CurrentState + " Ended");
}
Differences
The following table summarises the similarities and differences between regular Animancer Events and End Events:
Animancer Events | End Events |
---|---|
Both types of events can be configured in the Inspector using Transitions. |
|
Both types of events are cleared whenever you play another animation. | |
Can have multiple regular events per state. | Only one end event per state. |
Each event is triggered only once when its specified time passes (or with each pass of a looping animation). | End Events are triggered every frame after the specified time has passed. This ensures that even if the animation has already passed the end when you register the event, it will simply trigger next frame instead of not triggering at all and probably leaving the character stuck in that state. |
Every regular event must have a valid time (not NaN ). |
The default End Event time is NaN , which causes it to automatically determine which value to actually use at runtime based on the play speed: positive speed plays forwards and ends at normalized time 1 while negative speed plays backwards and ends at 0). |
- Despite the name, End Events do not inherently do anything to end the animation. You can do anything you want using the callback.
- You can also use End Animation Events to trigger whatever
OnEnd
callback you register, but that is generally much less convenient.
Coroutines
In coroutines you can yield return
any AnimancerState
to wait until it finishes. Specifically, it will wait until the state either stops playing or passes its end time (set using code or Transitions as described above).
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private AnimationClip _Animation;
void Awake()
{
StartCoroutine(CoroutinePlayAnimation());
}
IEnumerator CoroutinePlayAnimation()
{
Debug.Log("Starting animation");
var state = _Animancer.Play(_Animation);
yield return state;
Debug.Log("Animation ended");
}
You can also yield an entire Layer or AnimancerComponent
to wait for all their states to finish.
Note that yielding a state does not create Garbage, but starting a coroutine does.
Manual
You can keep a reference to the AnimancerState
returned by any of the AnimancerComponent.Play
methods and check its AnimancerState.NormalizedTime
every update (once the value reaches 1 the animation is finished):
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private AnimationClip _Animation;
private AnimancerState _State;
void Awake()
{
_State = _Animancer.Play(_Animation);
}
void Update()
{
if (_State.NormalizedTime >= 1)
Debug.Log("Animation ended");
}
Since states are kept in an internal dictionary, you can also get them quite efficiently when needed:
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private AnimationClip _Animation;
void Awake()
{
_Animancer.Play(_Animation);
}
void Update()
{
var state = _Animancer.States[_Animation];
if (state.NormalizedTime >= 1)
Debug.Log("Animation ended");
}
Note that if a state has not already been created for the animation (because it has not yet been played) then _Animancer.States[_Animation]
will throw an exception so you may wish to use _Animancer.States.TryGet(_Animation, out var state)
or _Animancer.States.GetOrCreate(_Animation)
instead.