animancer
animancer copied to clipboard
Calling `AnimancerComponent.Play` more than once causes `AnimancerEvent`s to fire more than once on a looping animation
Environment
- Animancer Version Number: 7.4.2
- Animancer Pro or Lite: Pro
- Unity Version: 2022.3.2f1
- Platform: Windows 11 Home Version 22H2
Description
When adding Animancer events using ClipTransition.Events.Add()
on a looping ClipTransition
, the event fires once per loop as expected. However, if that event's callback includes a call to AnimancerComponent.Play()
on that same ClipTransition
, the Animancer event will fire every frame from then on.
This seems like a bug as the documentation for AnimancerComponent.Play()
states, "This method is safe to call repeatedly without checking whether the transition
was already playing."
Reproduction
Steps to reproduce the bug:
- Create a game object with an animator, an animancer component, and this script:
using UnityEngine;
using Animancer;
public class LAB_AnimationLoop : MonoBehaviour {
[SerializeField] AnimancerComponent animancer;
[SerializeField] ClipTransition transition;
void Awake() {
transition.Events.Add(0.99999f, () => {
Debug.Log("Cycle Complete");
animancer.Play(transition);
});
}
void Start() {
animancer.Play(transition);
}
}
-
Remember to drag the Animancer component and an animation clip into the serialized fields using the Unity editor. The animation must be LOOPING animation. (I have not tried this with a non-looping animation, but perhaps the same thing would happen?)
-
Press play on the Unity editor and notice how "Cycle Complete" will be logged every frame after one loop of the animation.
-
Comment the line that goes
animancer.Play(transition)
and press play again. -
Notice that "Cycle Complete" only logs once per loop as expected.
Thanks for the detailed bug report, that made it really easy to find the issue.
The fix is pretty simple:
- Open
AnimancerState.EventDispatcher.cs
. - Go to the second
internal AnimancerEvent.Sequence Events
property in that file. - Add this at the end of the setter:
if (_State != null)
_PreviousTime = _State.NormalizedTime;
I only found one public AnimancerEvent.Sequence Events
in that file. Did you mean the internal AnimancerEvent.Sequence Events
? I added your code to the internal
property, and that fixed the issue.
Thanks for the rapid response!
Yeah, I must have only made the second one public
since releasing the last version.
I'll keep this issue open so people can see it until I release the next version with the bug fixed.