• Runtimes
  • [Spine-JS] Playing animation in reverse

So, I've been trying to get animations to play in reverse. According to some other posts, reverse should work with spine.Animation.

However, the state of the bones is not being reset correctly to the first frame.
This is because every timeline checks if the time that is passed to apply is before its first frame, and if it is, nothing is done. What should happen when reversing is that the first time reaching a time that is equal to or less than the first frame of a timeline, the first frame of that timeline is applied. This way, when the animation is reversed to the first frame, each timeline has its bone reset to the state is was in on the first frame.

Related Discussions
...
  • Змінено

The special case for the first key would only be valid when reversing. Eg, the first key on my timeline is on frame 10. Going forward, this key shouldn't be applied for frame 5 (only frames >= 10). Going backward you want this key to be applied for frame 5 (all frames <= 10).

Thinking a bit more about your proposed special case for the first key, let's say again the first key on my timeline is on frame 10 and it is for scaleX. When the animation is applied going forward, scaleX is not modified until frame 10. Until frame 10, the state of scaleX can be anything. It can be from the setup pose, from some other animation, from code that set it, etc. When reversing, applying the scaleX frame 10 for frames <= 10 does not guarantee you will end up in the same pose as when the animation was played forward.

I think the only sane way to handle being able to play animations both forward and backward is to have a key at frame zero (and maybe a key at the last frame?) for all timelines.

Lets say the first key on my timeline is on frame 30 at 1 sec.

I pass in 1.3 seconds, the bone is applied to a state that is between frame 30 and the next one. Next I pass in 0.9 seconds, which is before the first frame of the timeline, so the timeline is skipped. This means that the bone is the same state that it was in at 1.3 seconds, not, as it should be, at the state of frame 30.

Every timeline has a line like follows:

if (time < frames[0]) return; // Time is before first frame.

something like

if (lastTime > frames[0] && time < frames[0]) {
    //Apply frame 0 and return.
}

Could be used in order to apply the first frame of a timeline once in a backwards animation.

But I guess having a key on frame zero for each timeline and always pass in 0 to apply the first frame would work.

I see. That seems like it could work. I'm not sure the extra checks are better than setting a key at zero.

Just thought of something - while the solution of setting key frames at frame 0 works for most timelines, it would not work for event timelines. The event timeline seems like it would need a redo in order to work with a reversed animation. Actually, the event timeline would fire all events after lastTime every frame for reversed animations:

if (lastTime > time) { // Fire events after last time for looped animations.
         this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha);
         lastTime = -1;
4 дні пізніше
martinr написав

Just thought of something - while the solution of setting key frames at frame 0 works for most timelines, it would not work for event timelines. The event timeline seems like it would need a redo in order to work with a reversed animation. Actually, the event timeline would fire all events after lastTime every frame for reversed animations:

if (lastTime > time) { // Fire events after last time for looped animations.
         this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha);
         lastTime = -1;

I would like this fixed too 🙂