nngafook

Hey guys! Two quick questions...

1) Is there a way to loop a part of an animation? Even if only through code/unity.
Example: I have a run animation that has a start and an end animation. So I was hoping I could just make one animation, with all three parts (the start, the end and the running loop), and then just play the animation, loop the middle till the character gets where he's running to, then play the rest of the animation. (As I'm typing this, it sounds way too hopeful to be a real thing). But that leads to my second question..

2) In unity, I went into the source code and found that I could do something along the lines of...
skeletonAnimationObject.skeletonDataAsset.GetSkeletonData(false).FindAnimation("runstart"). Is that the only way to check if an animation exists on a skeleton? I wanna be able to know if there's a pre and post animation for specific animations, and play those instead of going directly to (in this case) the running animation.

Thanks!!
nngafook
  • Posts: 28

Pharan

An Animation object is the stateless animation data which holds a collection of Timelines, such that you can say:
myAnimation.Apply(skeleton, timeInSeconds); // simplified parameters
And it will pose the skeleton according to that point in time in the animation.

What determines looping behavior is whatever controls applying your animation.
By default, it is AnimationState, which keeps time and stores the states of animations and how they are supposed to play back.
In Unity, the AnimationState is SkeletonAnimation's .state field.

1) AnimationState does not automatically do what you're looking for above.
What you're looking for is a bit higher level and you should implement it yourself according to your needs. It's typically implemented as an extra layer that communicates with AnimationState.

2) There's currently no way to mark "pre-" and "post-" or whatever other semantic designation you want on your animations in Spine editor so there's nothing for the runtime to check for that sort of thing. Best you can do right now is have a naming scheme.
User avatar
Pharan
  • Posts: 5366

nngafook

Hey, thanks for the reply!

Sorry, I didn't mean that I wanted to check for a pre/post animation marked animation. I want to say something like:
void PlayIdle() {
if (skeleton.FindAnimation("runPre") != null) {
PlayPreRun();
}
else {
PlayRun();
}
}
Pseudo code of course. So my second question was more about, if there's an easy way to do that skeleton.FindAnimation.

And to point 1... Sorry, I got a bit lost. Do you mean that I can... create an animation with (let's just say) frames 0 - 10 is a pre run animation, 11 - 20 is the run loop, 21 - 30 is run end, and then in code basically play the animation but specific frames to loop based on which state of the animation is needed?

Thanks again! As always, super helpful!!
nngafook
  • Posts: 28

Pharan

1) AnimationState does not automatically do what you're looking for above.
I meant what it doesn't do by itself, you have to program it yourself, with code.
The current version of AnimationState cannot play specific frames in a loop, only whole animations. That is an upcoming feature. Unforunately, no ETA yet.

Either way, specifying where the loop starts or ends is currently not something that you can store in Spine as part of the skeleton or animation data, so you have to find a place to store that yourself too.
User avatar
Pharan
  • Posts: 5366

kane

I've started evaluating Spine this morning,
and looping a segment of an animation is one of the things I need as well.

So I started looking at the method AnimationState.SetAnimation, it seemed at first easy to implement:
/// <summary>Set the current animation. Any queued animations are cleared.</summary>
public TrackEntry SetAnimation (int trackIndex, Animation animation, bool loop) {
if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null.");
TrackEntry entry = new TrackEntry();
entry.animation = animation;
entry.loop = loop;
entry.time = 0;
entry.endTime = animation.Duration;
SetCurrent(trackIndex, entry);
return entry;
}
So I started adding an overload on SetAnimation, with time boundaries that would set the animation segment, with the following signature:
public TrackEntry SetAnimation(int trackIndex, Animation animation, bool loop, float startTime, float endTime)
And this was the beginning of dealing with quite a big mess :rock:
I had to add a startTime field on class TrackEntry.

After tweaking here and there, I finally got it working, (except when two animations are Mixing, I haven't tried there is probably a fix to add). So this is not a complete work yet, but it's start.
Please let me know if it's a good start =)

Here is the code changes attached

Note: I'm using Monogame, not unity, but these files are common
You do not have the required permissions to view the files attached to this post.
kane
  • Posts: 4

Pharan

Thanks for sharing!
I don't recommend going beyond the absolute bare bones functionality that works for you right now since, as I've said, this is a planned feature that's almost done on the official runtime.
New logic for AnimationState that handles this even in mixing is already there in java form in the dev branch of the spine runtime git. GitHub - EsotericSoftware/spine-runtimes at dev
It will likely be usable when Spine 3.5 comes out of beta.

The other end of it— saving/marking this information on the editor side— has no ETA.
User avatar
Pharan
  • Posts: 5366


Return to Unity