In this recipe, we'll show how the jumping animation can be handled in the animation manager control from previous recipes. Why does this require its own recipe? Animation-wise, jumping is usually a set of sequenced animations. If we look at Jaime, for example, there's JumpStart
, Jumping
, and JumpEnd
. Normally, sequenced animations can be handled in the onAnimCycleDone
method; when one animation ends, it can trigger the next. Jumping is different though since the middle jumping animation is indefinite and is on a loop. How long it plays depends on how long the character is in the air, which is driven by the gameplay or its physics.
You can handle jumping animations by performing the following steps:
jumpStarted
and inAir
.onAction
method, as shown in the following code. The jumpStarted
Boolean is used to let the class know that other animations should not start while the character is the jumping state:public void onAction(String binding, boolean value, float tpf) { if (binding.equals("Jump") && value) { jumpStarted = true; setAnimation(Animation.JumpStart); } }
onAnimCycleDone
method should switch animations back to the jumping action once JumpStart
has finished playing. We also set inAir
to true
, as shown in the following code:public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { if(channel.getLoopMode() == LoopMode.DontLoop){ Animation newAnim = Animation.Idle; Animation anim = Animation.valueOf(animName); switch(anim){ case JumpStart: newAnim = Animation.Jumping; inAir = true; break; } setAnimation(newAnim, channel); } }
controlUpdate
method is suitable to check whether the character has landed after jumping (or falling). We check this directly in BetterCharacterControl
and change the animation if it is back on the ground, as shown in the following code:protected void controlUpdate(float tpf) { if(inAir){ BetterCharacterControl charControl =spatial.getControl(BetterCharacterControl.class); if(charControl != null && charControl.isOnGround()){ setAnimation(Animation.Idle); jumpStarted = false; inAir = false; } } }
The implementation relies on the listener pattern where this control receives a notification of user actions from an external input class. In this project, we have a separate class that controls the character.
This onAnimCycleDone
method is called by the AnimControl
method when an animation has finished with one cycle (both looping and non-looping animations). Normally, when an animation ends, we'll want to switch to the idle animation to stop it from freezing. When JumpStart
is finished, however, the character is most likely in midair and thus switches to a suitable looping animation. The inAir
Boolean is used so the class knows it should start checking for when the character lands again.
Depending on the size of a project, the control class for the character and this animation-managing class might be merged into one. This should make some things easier, while the class itself might get bulky as more functions are implemented.
The controlUpdate
class is called automatically with every tick, and here we can see whether the character is still airborne. In this implementation, BetterCharacterControl
is used, and it has a method to see whether it is on ground. Jaime has a JumpEnd
animation, but idle seems to work better with some blending.
13.59.209.131