• Unity
  • No mix at a higher track (sometimes)

Hi there,

I'm having an issue with an animation on a higher track not appliying any mix at all (it snaps to frame 0 instantly).

My simplified use case is that I have an Idle animation on track 10, then track 20 is used for "secondary" animations such as raising an arm, carrying a tray, or whatever pose I want to use in addition to the base idle that includes the character breathing (so I don't need to include that on dozens of other animations).

So, apart from all the troubleshooting I'm trying to do, what I'd first need to confirm with you guys is if I actually understand how to play that new animation on the secondary, higher track.

Is it okay to use Set or Add, regardless of the current state of the track?

I mean, does it matter if I use Set with a track that is already playing an animation? Or if that is the case then I'd need to use Add if I ever expect any mixing happening?

The thing is, when I test how those multiple animations play simultaneously on the Preview windows on the editor, it doesn't look like I need to use additive at all. Both Set and Add modes seem to mix in all cases. But not in my project.

So, does it matter if there is something already playing?

Thanks!

Related Discussions
...

Yo Abelius :yes:

If a track is empty (not playing an animation) and you use SetAnimation or AddAnimation, it will instantly snap to the first frame of the animation.

To have it mix in, use SetEmptyAnimation (or AddEmptyAnimation) first, and then apply your actual animation.

You're correct that the Preview window in Spine seems to always smoothly mix in, and so it can look differently then in Unity.

Note: I use SkeletonAnimation for everything and not SkeletonMecanim, so the following info only pertains to SkeletonAnimation.

What I do when I want to apply an animation on a higher track, but I want it to mix in smoothly regardless of whether or not there is already an animation playing on that track is to check if that track already has an animation playing on it - if so, I use SetAnimation, if not I use AddAnimation:

<Old code removed, see below>

I wrote that code a while back, so there might be an easier way to check if the Track is empty.

Edit: Looks like a better way to check if a track is empty is: skeletonAnimation.AnimationState.GetCurrent(trackIndex). Note that it can return Null.

Also another thing to look out for - if you play an animation on the higher track and just let it finish, it will remain "freeze framed" on the final frame of the animation. So if you want to do something like lets say... the player is running and then they wave their hand. The lower track is playing the running animation loop. Then you Add (or Set) the Wave animation on the higher track and at the same time queue up an Empty Animation to play immediately after the Wave animation by doing skeletonAnimation.AnimationState.AddEmptyAnimation(). That way as soon as the Wave animation completes, the EmptyAnimation will begin and it will mix out the Wave animation into an empty track.

If you've got any follow up questions lemme know! (won't be able to answer until tomorrow though)

Jamez0r escribió

If a track is empty and you use AddAnimation, it will mix into the animation.

Actually this is the same as using SetAnimation. To mix you need 2 animations. You won't get mixing unless you play an animation, then use AddAnimation. This is what TrackEntry setEmptyAnimation (and addEmptyAnimation) is for. You mix from nothing, set an empty animation (so you get the setup pose), then set the animation you want to mix to, using a mixDuration.

Ah, so my guess was more or less correct. Thank you both for confirming. 🙂

My problem was that I had faulty logic in checking if the track was already playing an animation or not (didn't use a runtime command like skeleton.state.GetCurrent(track.Value), so my game interpreted it needed to use Set, when it should have used Add.

Jamez0r escribió

Also another thing to look out for - if you play an animation on the higher track and just let it finish, it will remain "freeze framed" on the final frame of the animation.

Oh, I didn't know this.

The thing is, I was very confused because it only happened when I was testing the game outside the editor (it becomes unplayable after two minutes in the Editor), and I passed through several scenes before the ones with problems. So it might be there was indeed some "unfinished business" in the track, from the previous scenes.

Many of my secondary animations are just 0-frame poses, not multi-frame animations to be looped. Most of the time I just want to modify some bones positions. And this problem only happened with those 0-frame poses.

Another potential issue I've seen in my PlayMaker action code is that I'm using SetEmptyAnimation instead of AddEmptyAnimation for the Add command...:

case AnimationCommand.Add:
    skeleton.state.SetEmptyAnimation(track.Value, mixDuration.Value);
    TrackEntry entryadd = skeleton.state.AddAnimation(track.Value, animationName.Value, loop.Value, delay.Value);
    entryadd.MixDuration = mixDuration.Value;
    entryadd.TimeScale = timeScale.Value;
    entryadd.TrackTime = startTime.Value;
    entryadd.Alpha = alpha.Value;
    break;

Should I change that line for AddEmptyAnimation instead?

Nate escribió
Jamez0r escribió

If a track is empty and you use AddAnimation, it will mix into the animation.

Actually this is the same as using SetAnimation. To mix you need 2 animations. You won't get mixing unless you play an animation, then use AddAnimation. This is what TrackEntry setEmptyAnimation (and addEmptyAnimation) is for. You mix from nothing, set an empty animation (so you get the setup pose), then set the animation you want to mix to, using a mixDuration.

Whoops, thanks for the correction - updated my post :yes:


Abelius escribió

Should I change that line for AddEmptyAnimation instead?

The difference between SetEmptyAnimation and AddEmptyAnimation is that SetEmptyAnimation applies the empty animation immediately, whereas AddEmptyAnimation queues the empty animation to be executed after the currently playing animation (or any other animation that is already queued up). If the track is currently empty, then both SetEmptyAnimation and AddEmptyAnimation will execute immediately.

I'm not sure what your goal is with the Playmaker "Add" command, but if the goal is to apply an animation smoothly (mixing in) then you only need to use an Empty Animation if the track is currently empty. If there is already an animation on the track, you should use SetAnimation(newAnimation) and not apply an Empty Animation at all (for mixing into the new animation).

So overall something like this, where 1 is your trackIndex:

if (skeletonAnimation.state.GetCurrent(1) == null) {
    skeletonAnimation.AnimationState.SetEmptyAnimation(1, 0.2f);
    skeletonAnimation.AnimationState.AddAnimation(1, "newAnim", false, 0);
} else {
    skeletonAnimation.AnimationState.SetAnimation(1, "newAnim", false);
}

//If you don't want it to "freeze frame" at the end of the animation
if (mixBackOutToEmptyAfterwards) {
    skeletonAnimation.AnimationState.AddEmptyAnimation(1, 0.2f, 0f);
}

Exactly right, thanks for helping out Jamez0r!