In short: I am trying to scrub/lerp an animation, it works but sometimes it lerps the reverse way.
In long: My character has an aim animation, 10 frames long, where he aims from down (-90 degrees) to up (90 degrees). And during the animation he also changes draw order, and some other stuff. The point is, I want to be able to set a value between 0 and 1, to determine where the animation should be. My code works so far, but it has a bug where it sometimes lerps the animation the opposite way. Meaning he aims up when he should aim down. Even though nothing in my debug seems to be the issue: the aim angle is correct, we are on the correct animation, seems to be the correct duration etc. Its's like the animation started reversed, or its trying to mix between the last animations pose (up) and the new animations pose (down), so it becomes up-down, instead of down-up. I don't know. Am I missing some line of code? I've tried skeleton.SetToSetupPose(); but doesn't seem to help.
private void Update()
{
if (someConditions)
{
SetAimAnimation(animation01);
}
else
{
SetAimAnimation(animation02);
}
}
// Will lerp an animation from start to finish depending on our current aim angle, ranging from -90 (down) to 90 (up).
private void SetAimAnimation(AnimationReferenceAsset animation, float currentAngle, float downAngle = -90, float upAngle = 90)
{
// even though I brute force, e.g. clear the track and set every frame it will sometimes get revered
//animationState.ClearTrack(aimLayer);
//var trackEntry = animationState.SetAnimation(aimLayer, animation, false);
// will only play the animation if its new, otherwise returns the current track entry
var trackEntry = SetAnimation(aimLayer, animation);
trackEntry.TimeScale = 0;
// Calculate the animation time based on the progress
var animationProgress = Mathf.InverseLerp(downAngle, upAngle, currentAngle);
var animationDuration = trackEntry.Animation.Duration;
var animationTime = animationDuration * animationProgress;
// Scrub the animation to the desired time
trackEntry.TrackTime = animationTime;
Debug.Log($"Animation Progress: {animationProgress}, Animation Duration: {animationDuration}, Animation Time: {animationTime}");
Debug.Log($"Track Entry: {trackEntry}. Track Time: {trackEntry.TrackTime}, Animation Name: {trackEntry.Animation.Name}, Animation Loop: {trackEntry.Loop}");
// Update the skeleton to reflect changes
skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);
}
/// Will only play the animation if it's new, won't play animation if it's the same
private TrackEntry SetAnimation(int trackIndex, AnimationReferenceAsset animation, bool loop = false)
{
var animationName = animation.Animation.Name;
var currentTrackEntry = animationState.GetCurrent(trackIndex);
var currentAnimation = currentTrackEntry?.Animation;
if (currentAnimation == null || currentAnimation.Name != animationName)
return animationState.SetAnimation(trackIndex, animation, loop);
return currentTrackEntry;
}