Hi,
I've created my 2D Player prefab using Spine animation and I'm trying to ensure that certain animations do not get mixed with others. To achieve this, I came up with a script that plays specific animations on a higher track index.
I used the script below with the Character: Animate Action. I set the Method to Play Custom and the Track Index to 10. However, this script still mixes the animation on the special track with the idle animation.
Did I miss anything here? Is there something specific in the Character: Animate Action that handles animations in a way that might cause this mixing issue? For example, does it always trigger the idle animation by default?
Thank you!
P.S. I am aware that the script below is more of a Spine issue. I'm only sharing it to help with understanding my context.
using Spine.Unity;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Spine.Unity.Examples
{
public class AnimationMixingSpine2D : MonoBehaviour
{
const int BlinkTrack = 1;
const int MainTrack = 0;
const int EyeTrack = 2;
const int SpecialTrack = 10; // Track for special animations like back-opening-locker
public AnimationReferenceAsset idleAnimation;
public AnimationReferenceAsset walkAnimation;
public AnimationReferenceAsset blinkAnimation;
public AnimationReferenceAsset lookIdleAnimation;
public AnimationReferenceAsset lookRightAnimation;
public AnimationReferenceAsset lookDownAnimation;
public AnimationReferenceAsset backOpeningLockerAnimation; // Added backOpeningLockerAnimation
public float minimumDelay = 0.15f;
public float maximumDelay = 3f;
public bool persistentEyeAnimation = false;
private List<Spine.Animation> allowedAnimations;
private SkeletonAnimation skeletonAnimation;
private AnimationReferenceAsset currentEyeAnimation;
IEnumerator Start()
{
skeletonAnimation = GetComponent<SkeletonAnimation>();
if (skeletonAnimation == null) yield break;
// Initialize the list of allowed animations
allowedAnimations = new List<Spine.Animation>
{
idleAnimation.Animation,
walkAnimation.Animation
};
// Get the AnimationStateData to set up mixing
var stateData = skeletonAnimation.AnimationState.Data;
stateData.SetMix(idleAnimation.name, blinkAnimation.name, 0.1f);
stateData.SetMix(walkAnimation.name, blinkAnimation.name, 0.1f);
stateData.SetMix(blinkAnimation.name, idleAnimation.name, 0.1f);
stateData.SetMix(blinkAnimation.name, walkAnimation.name, 0.1f);
skeletonAnimation.AnimationState.Event += HandleEvent;
skeletonAnimation.AnimationState.Complete += HandleComplete;
// Set default eye animation to look idle
currentEyeAnimation = lookIdleAnimation;
skeletonAnimation.AnimationState.SetAnimation(EyeTrack, currentEyeAnimation, true);
while (true)
{
var currentAnimation = skeletonAnimation.AnimationState.GetCurrent(MainTrack)?.Animation;
if (allowedAnimations.Contains(currentAnimation))
{
skeletonAnimation.AnimationState.SetAnimation(BlinkTrack, blinkAnimation, false);
}
else
{
skeletonAnimation.AnimationState.SetEmptyAnimation(BlinkTrack, 0.1f);
}
yield return new WaitForSeconds(Random.Range(minimumDelay, maximumDelay));
}
}
private void HandleEvent(TrackEntry trackEntry, Spine.Event e)
{
// Event handling logic if needed
}
private void HandleComplete(TrackEntry trackEntry)
{
if (trackEntry.TrackIndex == MainTrack)
{
var currentAnimation = skeletonAnimation.AnimationState.GetCurrent(MainTrack)?.Animation;
if (!allowedAnimations.Contains(currentAnimation))
{
skeletonAnimation.AnimationState.SetEmptyAnimation(BlinkTrack, 0.1f);
}
// Reapply the current eye animation if persistence is enabled
if (persistentEyeAnimation && currentEyeAnimation != null)
{
skeletonAnimation.AnimationState.SetAnimation(EyeTrack, currentEyeAnimation, true);
}
}
}
public void SetEyeAnimation(AnimationReferenceAsset eyeAnimation, bool persist)
{
if (eyeAnimation != null)
{
currentEyeAnimation = eyeAnimation;
persistentEyeAnimation = persist;
skeletonAnimation.AnimationState.SetAnimation(EyeTrack, currentEyeAnimation, true);
}
}
public void PlayBackOpeningLockerAnimation()
{
// Clear the SpecialTrack to ensure no other animations are mixed
skeletonAnimation.AnimationState.ClearTrack(SpecialTrack);
skeletonAnimation.AnimationState.SetAnimation(SpecialTrack, backOpeningLockerAnimation, false);
// Optionally add an empty animation after back-opening-locker animation to avoid freeze frame
skeletonAnimation.AnimationState.AddEmptyAnimation(SpecialTrack, 0.2f, 0f);
}
}
}
It looks like you're new here. If you want to get involved, click one of these buttons!
Comments
Idle is played each frame normally, but not when the character is in "custom" mode.
The Spine Integration places the character in custom mode when the Character: Animate Action is used to play a custom animation, but it comes out of it automatically when the animation has completed.
Do you have Return to idle after? unchecked?
Thanks for your quick response! I can't seem to find the "Return to Idle after" option in the Character: Animate Action. I'm sorry if this is a basic question, but where can I find this option to turn it off? Thank you!https://imgur.com/a/mZEnqif
It requires Wait until finish? to be checked first.