Forum rules - please read before posting.

Play Spine Custom Animation using Character Animate

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);
        }
    }
}

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?

  • edited July 2024

    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.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.