- संपादित
[spine-c] 3.5, skeleton resets after track ends all anims
In previous C runtime versions skeletons always stayed in the exact same state (I mean bones transformations, etc..) they were left after their animation(s) has ended. And that was pretty useful (i.e. I could call setAnimation a few updates later, and not right away upon getting "complete" event, and during that time - picture on the screen stays consistent).
After the recent update though skeletons started to reset themselves right after track ends it's last animation. And I don't even sure if that was an intended change in the logic.
It was also useful in cases where I need to set animation timeline to its end and take the final bones positions or some other info. Now I have to set trackTime to trackEnd * 0.99 (which is not entirely correct) instead of 1.0, otherwise I get wrong values;
Yeah, I'm also interested to leave animation at last frame. Is it possible?
This is working as intended.
If you want to hold the last pose, set trackEnd
to positive infinity or a maximum type value.
Hm, but I need complete event + keep last position. If I set trackEnd to infinity, do I get complete event?
Judging from the code, you should get the Complete event.
spine-runtimes/AnimationState.c at master
AnimationState.c
if (entry->loop ? (trackLastWrapped > FMOD(entry->trackTime, duration))
: (animationTime >= animationEnd && entry->animationLast < animationEnd)) {
_spEventQueue_complete(internal->queue, entry);
}
AnimationState.java
// Queue complete if completed a loop iteration or the animation.
if (entry.loop ? (trackLastWrapped > entry.trackTime % duration)
: (animationTime >= animationEnd && entry.animationLast < animationEnd)) {
queue.complete(entry);
}
For looping animations we default trackEnd
to essentially forever. For non-looping we default it to the animation duration. Maybe it would make sense to use the same default for both looping and non-looping? That would mean by default animations continue being applied, even if non-looping, and if you want the animation to stop being applied you have to explicitly set trackEnd
or play another animation. Thoughts?
Looks good for my side.
We have made the change so trackEnd
defaults to forever for both looping and non-looping animations. This will make it to Git master
for all runtimes soon.
I just tried the latest version from master but for some reason AnimationStateListener's end method isn't being called [libgdx]
That's because animations continue being applied until a new animation is set or the track is cleared. See TrackEntry trackEnd
.
You could also listener for complete
instead of end
.
Sorry if AnimationState functionality feels like moving target, but we felt the trackEnd
default value change was worth it. The sooner the less overall pain it causes. We don't have plans for any other changes in 3.5 that affect how the API is used.
Yes I completely understand and agree that if aggressive API changes need to be made, the sooner the better.
Thanks for the complete vs end tip, that might solve it all
Nate लिखाWe have made the change so
trackEnd
defaults to forever for both looping and non-looping animations. This will make it to Gitmaster
for all runtimes soon.
Does this now mean that attachment stuff over multiple tracks will now work.
i.e.
SetAnimation("attachment on",0,false) //999 frames
AddAnimation("attachment Off",1,0.5/delay/, false)// 1 frame
attachment off will continue to be applied. iirc you suggested that I needed to set the track end time to #inf
Yes, that should work now.
- संपादित
Nate लिखाThat's because animations continue being applied until a new animation is set or the track is cleared.
I was updating some legacy code to the 3.6 runtime, and my End Listeners stop working. By comparing with my previous version, I found out that in the AnimationState.c update function I had this
/* End non-looping animation when it reaches its end time and there is no next entry. */
if (!current->loop && current->lastTime >= current->endTime) spAnimationState_clearTrack(self, i);
and now there's this
/* Clear the track when there is no next entry, the track end time is reached, and there is no mixingFrom. */
if (current->trackLast >= current->trackEnd && current->mixingFrom == 0) {
I understand the changes made in 3.5 to trackEnd, but not how to get the same I had before. In order to keep the previous pose after the animation, trackEnd should be kept at INT_MAX, but then how should the track be cleared in order to fire the End Event?
Thanks for the quick response.
Quickly trying to use AnimationStateListener complete instead of end in some cases, resulted in a better result, but still not the same as before the update. Probably more changes would be needed in other functions, which we probable can't make now.
However, I think I am missing the right usage for the End Listeners then (and how to use them, since trackEnd doesn't let the track being cleared), and how to accomplish the same behaviour as before.
If you want trackEnd
to clear the track when the animation duration is reached:
TrackEntry entry = animationState.addAnimation(...);
entry.trackEnd = entry.animation.duration;
This was the old behavior for non-looping animations. The default was changed to match looping animations, which continue being applied. There was discussion and the reasoning was good, though I don't remember it off the top of my head.
If you want the animation to continue being applied past its duration, that is the default behavior but end
won't fire, as you found, because end
means the track entry is done and won't be applied again.
Ok, last question :p
Is it possible to keep the last pose after the animation duration is reached, other then by having the trackEnd set to infinite?
In other words, can I have both end event and keep last position.
When trackEnd
is reached, the track is cleared. When the track is cleared, the animation will no longer be applied, so end
occurs. Instead of using trackEnd
you could clear the track yourself at the right time.
See exactly when each event occurs here:
AnimationStateListener
If you don't want to use trackEnd
to clear the track, then the end
event isn't what you want.
Again, you can leave trackEnd
so the animation continues being applied, then listen for complete
which for a non-looping animation happens once when the animation duration is reached.