StateHandler/AnimationTest
The StateHandler is the predicate that you provide to the controller when creating it.
Overview
This predicate provides an AnimationTest instance that provides all the relevant context for the controller to
decide how to animate for the current render pass.
The predicate is called every render frame to determine its current state of animation.
The predicate should be considered a snapshot of animating, and not a start/stop condition for animations.
Example StateHandlers
See below for some examples of how you can use the AnimationTest instance to control animations.
Note that most or all of these examples are already built into GeckoLib, using DefaultAnimations.
Example 1 - Walk
In the example below, we have a controller that checks if the entity is currently moving.
If it is, it tells the controller to start or continue a walk animation, but if it isn't, stop animating.
We use the shortcut method setAndContinue to both set the animation and tell the controller to continue animating.
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(test -> {
if (test.isMoving())
return test.setAndContinue(DefaultAnimations.WALK);
return PlayState.STOP;
}));
}
Example 2 - Walk/Idle
In this example, we take the walking controller from the first example, and change it so that instead of stopping, the controller instead switches to an idle animation when the entity isn't walking.
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(test -> {
if (test.isMoving())
return test.setAndContinue(DefaultAnimations.WALK);
return test.setAndContinue(DefaultAnimations.IDLE);
}));
}
Example 3 - Spawning
In this example, we want to play an animation whenever the entity first appears, as a sort of 'spawning' animation.
We do this by checking if the entity's tickCount is less than or equal to the length of the animation, and if so, play it.
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(test -> {
if (MyEntity.this.tickCount <= 100)
return test.setAndContinue(MY_SPAWN_ANIMATION);
return PlayState.STOP;
}));
}
Example 4 - Attacking
In this example, we want to play an attack animation if the entity is swinging.
We do this by checking the entity's swinging state, and telling the controller to play the attack animation if it is,
or stop if it is not
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(test -> {
if (MyEntity.this.swinging)
return test.setAndContinue(DefaultAnimations.ATTACK_SWING);
return PlayState.STOP;
}));
}
The swinging boolean exists on all entities in vanilla, however Minecraft is particular in how it uses it.
See the #using the swinging boolean section for more information.
It's perfectly fine to repeatedly set an animation with every pass if it's already playing. GeckoLib will simply ignore it.
Using the swinging boolean
When creating entity attack animations, the commonly recommended method is to use the swinging boolean that vanilla's Entity
class holds.
This is good, however Minecraft's implementation of the field leaves some holes.
Firstly, if your entity does not extend Monster, you will need to manually increment the arm swing yourself, by inserting
the below code into your aiStep method:
@Override
public void aiStep() {
super.aiStep();
updateSwingTime();
}
Secondly, if your attack animation is longer than 6 ticks, you will need to adjust the swing duration of your entity, by inserting the below code into your entity's class:
@Override
public int getCurrentSwingDuration() {
// Change the number to the number of ticks your animation is long, + 1
// For example, a 1-second animation should return 21 here
return 6;
}