Search the API reference for "previous pose" and you'll find a few areas where an animation can leave the skeleton in the pose from when the animation was last applied. Eg, TrackEntry trackEnd
explains what happens at the end of a non-looping animation. If this is not what you want, you need to use an empty animation to mix to the setup pose.
It's suboptimal to store game state in the skeleton pose, since this couples the model (the state of your game world) with the view (the stuff that gets displayed). Eg, if you needed to serialize the game state, you'd need to serialize part of the skeleton pose (which attachments are shown). Or, imagine if you hit an enemy and needed to check what attachment is in a slot to know what weapon is equipped so you know how much damage to deal. A better organizational approach would be to store the state in the game's model and push that information to the view so it draws the right things as the model changes.
Mixing back to the setup pose is done for everything: bones, attachments, constraints, etc. The reasoning is not just for model/view separation. Imagine your animation shows some attachments for some visual effects, then it is interrupted in the middle of its playback. In this case you don't want the attachments to stay shown. In other cases, say if you are removing a sword from a sheath, you do want the attachments to stay shown. How can the animation system know what you want?
One solution is to apply animations based on the character's state in the model (idle, walking, running, etc), then apply any pose changes also based on the model (what weapon is equipped, ailment status, etc). Eg, the character is running so you apply running
, then the model says he has a sword equipped so you set the sword
attachment for the hand slot.
There are a couple approaches to determine which animation to play. Probably the best way is to have states in the model, then you set the current animation based on these states. Super Spineboy does this. This allows the model to be manipulated however is needed without worrying about particular animations, and the view will play the correct animations.
Another way is to consider each animation that is playing as part of the model. This can be tricky, since an animation being applied is really a TrackEntry, which has quite a lot of state.
Events can be used to trigger a change in the model at a particular time in an animation. However, this should be used carefully. Consider an animation that removes a sword from a sheath and the sword isn't visible until halfway through the animation. When does the model consider the sword as equipped? An event could be used which tells the model the sword is now equipped. In this case the model should have an equipSword
state, which knows to apply the equipSword
animation. Without such a state, if you just played the equipSword
animation to change the model using an event, and if you serialized the game state before the event happened, you'd lose the fact that the sword was about to be equipped.
Hopefully by now you've forgotten you even had a question! :clap: This got a bit long, but it's good to consider how your model and view/animations interact. It's very easy to tie them together, especially if you don't have serialization needs, but as the app grows this approach becomes more and more complex. Having your model decoupled from your view can be a pleasure to work with. That said, a scene graph like Unity inherently ties the model to the view (GameObjects) so it is more difficult to organize (I honestly don't know how, most Unity projects are a nightmare :bang: ).
As for solving your particular problem, unless you want to rework how you manage your game state, the easiest thing would be to modify AnimationState so it doesn't reset attachments to the setup pose. To hack her up, in AttachmentTimeline apply
change:
if (time < frames[0]) { // Time is before first frame.
...
}
To:
if (time < frames[0]) return; // Time is before first frame.
Also, in AnimationState applyMixingFrom, change:
if (timeline instanceof RotateTimeline)
To:
if (timeline instanceof AttachmentTimeline) continue;
if (timeline instanceof RotateTimeline)
I don't know about making this a setting, as it introduces the problem that animations which are interrupted may leave unwanted attachments shown. If by default all slots are reset as they are now and you disable that using a setting, then when changing animations you'd need to call setToSetupPose
on the slots you DO want reset.