• Unity
  • Dynamic timeline chance

Related Discussions
...

(Dynamic timeline CHANGE, sorry)

Hi,

I'm having trouble finding a way to change the playhead (timeline) of my Spine animation, dynamically from my C# code. I've been around the spine-unity runtime classes, but can't find a clue.

Basically what I have is an animation of my character moving his shield all around 360 degree. And I want to adjust the playhead of that animation according to the Mouse position, so his shield angle would match it. I had no worry achieving this with Adobe Flash and the MovieClip timeline (I just used gotoAndStop) but is there a way to do this with Spine and Unity ?

Thanks a lot for your time and help,

P.S: Spine is just amazing, I'm having a blast learning it 🙂

There is.

An Animation object has an Apply method.
You can get the animation object from the SkeletonData via this method: https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-csharp/src/SkeletonData.cs#L130.
You can find the SkeletonData object in your skeletonAnimation.Skeleton.Data.
Note that the skeleton is instantiated on Awake, so you have to do this find-stuff in Start.
You can also get the same SkeletonData object through your SkeletonDataAsset. It has a GetSkeletonData method.

To pose the skeleton according to a certain time in an Animation, you Apply that Animation to a Skeleton and pass it a time.
https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-csharp/src/Animation.cs#L56

The time is equivalent to the playhead of the dopesheet (where the dopesheet is 30fps, so "Frame 30" would be 1.0f meaning 1 second).

You can pass 0 as the lastTime parameter. and null for the events parameter. Both are used for event key capturing and slot attachments. Internally, the Spine.AnimationState system uses Animation.Apply to pose the skeleton from update to update.

un mes más tarde

Many thanks! That's exactly what I need. Have a wonderful day :party:


28 Jan 2016, 09:22


I re-open this topic because for a few hours I've been stuck again in the Timeline editing...
Considering this simple goToTime() function (nothing fancy, just shortcut basically) which is called after Start:

protected void goToTime (float pTime) {
    //skeletonAnimation.state.ClearTrack(0);
    getAnim(currAnimId).Apply(skeletonAnimation.skeleton, 0, pTime, true, null);
}

Problems:

  • If I don't call ClearTrack before, the Apply seems to have no effect on my animation which keeps playing.
  • If I do call ClearTrack, the playhead is changed properly with the new time, but the animation just stops there.

That's cool when you need a gotoAndStop (like in my original post), but now I need a gotoAndPlay ==> 5 hours of failure trying :doh:
What am I missing here?

P.S: Does a written Doc of the runtime will possibly be available at some point? That would be very convenient! I watched the cool tutorial videos but that can't replace a full library doc.

What's getAnim?

I recommend reading this: https://github.com/pharan/spine-unity-docs/blob/master/Animation.md#trackentry
I'll be adding a few things to elaborate, 'cause it looks like someone would get confused in the context of what you were trying to do.

In any case, here's a short description of what happens when you call SetAnimation:

  1. You call mySkeletonAnimation.state.SetAnimation.
  2. SkeletonAnimation's AnimationState generates a TrackEntry object (which stores current time of that animation playback instance) and adds it to its internal track system to be automatically managed, updated, and applied to the skeleton.
  3. SetAnimation returns the TrackEntry object so you can do whatever you want with it.

so you can say:

Spine.TrackEntry myTrackEntry = mySkeletonAnimation.state.SetAnimation(0, "run", true);
myTrackEntry.time = 0.5f; // jumps to the 0.5 seconds mark.
//myTrackEntry.lastTime = 0.5f; // Optional. Originally 0. prevents events within the 0-0.5 range from firing immediately. But also ignores Attachment keys right now. This will change in 3.0.

The code above will cause the animation to start playing at 0.5 seconds.
Then SkeletonAnimation's AnimationState object will continue to update and manage the TrackEntry itself.
Internally, it calls Animation.Apply every update based on the time stored in TrackEntry, and advances that time based on Unity's Time.deltaTime.

So if you don't store the TrackEntry when you call SetAnimation, you can retrieve it this way:

TrackEntry myTrackEntry = mySkeletonAnimation.state.GetCurrent(myTrackNumber); // can return null. always have a null guard before doing stuff.

At any point then, you can say

myTrackEntry.time = timeIWantToJumpTo;

And if you want it to stop but still keep applying (ie, not remove the TrackEntry from the track)

myTrackEntry.timeScale = 0f;
// timeScale is used to slow down or speed up a specific animation playback instance.
// It won't work with negative numbers.
// But 0 will cause it to pause until you set it to 1 again.

So a helper method would look like this:

public static Spine.TrackEntry JumpToTime (SkeletonAnimation skeletonAnimation, int trackNumber, float time, bool skipEvents, bool stop) {
     if (skeletonAnimation == null) return null;
     return JumpToTime(skeletonAnimation.state.GetCurrent(trackNumber), time, skipEvents, stop);
}

public static Spine.TrackEntry JumpToTime (Spine.TrackEntry trackEntry, float time, bool skipEvents, bool stop) {
     if (trackEntry == null) return trackEntry;
     trackEntry.time = time;
     if (skipEvents)
          trackEntry.lastTime = time;

 if (stop)
      trackEntry.timeScale = 0;

 return trackEntry;
}

28 Jan 2016 6:29 pm


Full documentation of the runtimes in general is here: http://esotericsoftware.com/spine-using-runtimes
It's helpful for low-level stuff.

The spine-unity documentation I originally linked is for Unity-specific things. https://github.com/pharan/spine-unity-docs/

getAnim() simply return => skeletonAnimation.skeleton.Data.FindAnimation(pId);

Just changed the function according to your explanations it works fine, thanks!
I did get confused quite a bit, to me FindAnimation was returning the actual animation that I wanted to tweak, when it was actually only the animation clip. But it's getting clearer. Thanks for the link of the doc, looks great, not sure how I missed that but that should prevent some future question spamming.

There is a Gauge rig in the example folder that is exactly this.

Mitch, he's asking about something else now. Gauge doesn't apply.

@SoulGame,

That's right. FindAnimation gets a Spine.Animation (animation clip data, with keys and timelines and stuff).
https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-csharp/src/Animation.cs#L36

GetCurrent gets the TrackEntry (an instance of animation playback).
https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-csharp/src/AnimationState.cs#L262

Yup, that makes sens. So much to learn! But it's definitely worth it.

Oops, was reading on mah phone. sorry.