martinr

When transitioning from one animation to another, if the call to AnimationState.apply for a skeleton is not called before the following update, the skeleton can end up in a wrong state according to the animation state. EDIT: This causes following calls to apply to set the wrong state on the skeleton.

See test case: https://github.com/smaren/spine-runtimes/blob/no-apply-in-transition-bug/spine-ts/webgl/demos/mixandapplybug.js
martinr
  • Сообщения: 24

badlogic

This actually works as intended. The AnimationState update() and AnimationState apply() are separated so the same state can be applied to multiple skeletons. If you don't call apply(), the skeleton will not change.
Аватара пользователя
badlogic

Mario
  • Сообщения: 2076

martinr

But I do call apply (line 29 in the test case). The issue is that apply does not set the correct state as it is in the animation state. According to the animation state, the translate of bone is at 0, 0. The skeletons bone is at 100, 100. Setting the animation state on another skeleton sets the correct state

I updated the test case to include another skeleton to show that their states differ:
https://github.com/smaren/spine-runtimes/blob/no-apply-in-transition-bug/spine-ts/webgl/demos/mixandapplybug.js

I see that the description can be a bit misleading. The issue is that missing one call to apply causes the following calls to apply to have a wrong state. Edited the OP to better reflect this
martinr
  • Сообщения: 24

Nate

I confirmed this is working by design. When you call AnimationState update twice in a row without AnimationState apply in between, the animation that mixed out misses its change to reset the values it was animating to the setup pose.
// Tick big enough to start the transition from one animation to the next.
state.update(0.101f);
state.apply(skeleton1);
System.out.println("1: x " + bone1.x + ", scaleX " + bone1.scaleX); // x 100.0, scaleX 1.0
System.out.println();

// translate_100_ms has been mixed out, the next apply will reset translation to the setup pose.
state.update(0.001f);
// There is no apply here!

// translate_100_ms is no longer applied, bone1 is left translated because there was no apply since last update.
state.update(0.2f);
state.apply(skeleton1);
System.out.println("1: x " + bone1.x + ", scaleX " + bone1.scaleX); // x 100.0, scaleX 2.0
System.out.println();

// bone1 still has x=100 because it never got reset to the setup pose.
state.apply(skeleton1);
state.apply(skeleton2);
System.out.println("1: x " + bone1.x + ", scaleX " + bone1.scaleX); // x 100.0, scaleX 2.0
System.out.println("2: x " + bone2.x + ", scaleX " + bone2.scaleX); // x 0.0, scaleX 2.0
full Java source

When an animation is applied, it only changes the properties it has timelines for. The last two calls to apply do indeed pose the skeletons identically, however the changes from the previous animation got left behind because it was not applied after it was done mixing out.
Аватара пользователя
Nate

Nate
  • Сообщения: 9264

martinr

I had understood it in such a way that applying an animation state to a skeleton would set exactly that state on the skeleton, citing the docs for apply: ... so the animation state can be applied to multiple skeletons to pose them identically.

Rather, in order to be certain that a skeleton has the correct state according to an animation state, the animation state must be applied to the skeleton after every update (maybe only when a TrackEntry is ending?). Is that correct?

I see it makes sense to only change properties that have timelines.
martinr
  • Сообщения: 24

Nate

The animation state does pose them identically, but only changes the properties the animations have timelines for. I'll try to clarify that in the API reference, as well as that apply should be called after update. Sorry for the gotcha!
martinr писал(а):in order to be certain that a skeleton has the correct state according to an animation state, the animation state must be applied to the skeleton after every update (maybe only when a TrackEntry is ending?). Is that correct?
Yes, that will ensure when an animation ends that the properties it has keys for are returned to the setup pose. Changes to properties (eg via your code) that are not keyed in animations are not affected. This allows for things like assigning an attachment to a slot based on game state -- the animation state won't change that attachment unless it has keys to do so. The same is true for bone transforms (eg to aim at an enemy) and other properties. If you do key properties, you can still override the animation's changes by setting their values after applying the animation state (every frame, but setting properties is cheap).

To be absolutely sure about the state of a skeleton, you can use Skeleton setToSetupPose or these more granular methods:
Skeleton setSlotsToSetupPose
Skeleton setBonesToSetupPose
Slot setToSetupPose
Bone setToSetupPose
Аватара пользователя
Nate

Nate
  • Сообщения: 9264

martinr

Thanks for thorough answers :)
martinr
  • Сообщения: 24


Вернуться в Bugs