FlixelAnimationStateMachine
View sourceclass
org.flixelgdx.animation.FlixelAnimationStateMachine
A lightweight finite state machine that drives a sprite's animations.
Why this exists
Calling playAnimation directly from gameplay code works, but it spreads animation rules everywhere: which clip plays for which behavior, which transitions are legal, what should happen when a one-shot clip finishes, and what side effects (sound, particles) a transition triggers. A state machine gathers those rules in one place so the gameplay code can simply say "I am now running" and trust the machine to play the right clip, reject illegal moves, and chain follow-up animations on its own.
What a state can describe
- the animation clip to play (or none, for an invisible logic-only state),
- whether that clip loops,
- an
auto-advancetarget, so a one-shot clip (such as an attack) automatically returns to another state the moment it finishes, optionally after adelay, onEnter/onExithooks for side effects, and- the set of
legal transitionsout of it.
Concepts and terminology
- State: one named mode the sprite can be in, such as
"idle"or"attack". The machine is in exactly one state at a time. Register states with FlixelAnimationStateMachine.addState(String, String). - Transition: a move from one state to another, requested with FlixelAnimationStateMachine.setState(String). Asking for the state that is already active is a no-op.
- Guard: a rule that decides whether a transition is allowed. Configured per source state with
State.allowTo(...); a state with no rule allows any move. - Entry / exit actions: callbacks run when a state is entered or left (
State.onEnter(...)/State.onExit(...)). - Auto-advance: an automatic transition that fires when a one-shot clip finishes (
State.autoAdvanceTo(...)), optionally after a delay. - Self-transition: deliberately re-entering the current state with setState(name, true), which replays its clip.
How it drives the sprite
The machine holds a reference to the sprite's FlixelAnimationController and subscribes to its FlixelAnimationController.onAnimationFinished signal, which is what powers auto-advance. You must still call sprite.update(...) every frame so the controller advances animation time and reports when clips end. If any state uses a delayed auto-advance, the machine's FlixelAnimationStateMachine.update(float) must also be called each frame so the delay can elapse. The easiest way to satisfy that requirement is to link the machine to the controller with FlixelAnimationController.setStateMachine(FlixelAnimationStateMachine), which makes sprite.update(...) tick both automatically. Alternatively, call FlixelAnimationStateMachine.update(float) yourself each frame.
Typical usage
// After loading frames and registering clips on the sprite:
var fsm = new FlixelAnimationStateMachine(player);
fsm.addState("idle", "idle").allowTo("run", "attack");
fsm.addState("run", "run").allowTo("idle", "attack");
fsm.addState("attack", "attack")
.autoAdvanceTo("idle") // one-shot: snaps back to idle when the clip ends
.onEnter(() -> sword.swing());
fsm.setState("idle");
// Link the machine so player.update(...) ticks it automatically - no separate fsm.update() needed:
player.ensureAnimation().setStateMachine(fsm);
// Each frame, just describe the situation; calling setState with the current state is a no-op:
if (attackPressed) fsm.setState("attack");
else if (speed > 0.1f) fsm.setState("run");
else fsm.setState("idle");
See Also: FlixelAnimationController, FlixelSprite.ensureAnimation
Constructors
FlixelAnimationStateMachine(FlixelSprite)
Creates a machine that drives the given sprite's FlixelAnimationController.
Parameters:
| Name | Description |
|---|---|
sprite | The sprite to animate; its controller is obtained via FlixelSprite.ensureAnimation(). |
FlixelAnimationStateMachine(FlixelAnimationController)
Creates a machine that drives the given controller.
Parameters:
| Name | Description |
|---|---|
controller | The controller whose registered clips the states refer to. |
Fields
onStateChanged
Fired with the new state name whenever the machine moves to a different state. Not fired for a no-op FlixelAnimationStateMachine.setState(String) call that targets the current state.
Methods
addState(String)
Registers a logic-only state with no animation clip. Entering it still fires hooks and FlixelAnimationStateMachine.onStateChanged, but plays nothing.
Parameters:
| Name | Description |
|---|---|
name | The logical state name. |
Returns: The new State for fluent configuration.
addState(String, String)
Registers a state that plays clipName (a clip already registered on the controller via addAnimation / addAnimationByPrefix) when entered.
Parameters:
| Name | Description |
|---|---|
name | The logical state name. |
clipName | The animation clip to play, or null for a logic-only state. |
Returns: The new State for fluent configuration.
removeState(String)
Removes a registered state. Does not change the current FlixelAnimationStateMachine.getState().
Parameters:
| Name | Description |
|---|---|
name | The state to remove. |
setState(String)
Moves to newState if the transition is legal. Calling this with the state that is already active is a cheap no-op, so it is safe to call every frame.
Parameters:
| Name | Description |
|---|---|
newState | The state to enter. |
Returns: true if the machine is now in newState, false if the transition was rejected as illegal.
setState(String, boolean)
Moves to newState, optionally re-entering it even if it is already active.
A forced re-entry replays the state's clip from the start and runs its onEnter hook again (but not onExit, since the machine never left). This is handy for retriggering a one-shot, such as attacking again mid-swing.
Parameters:
| Name | Description |
|---|---|
newState | The state to enter. |
force | true to re-enter even when newState is already active. |
Returns: true if the machine is now in newState, false if a real (state-changing) transition was rejected as illegal.
update(float)
Advances a pending delayed auto-advance. Only needed when a state uses a delay; immediate auto-advance and manual FlixelAnimationStateMachine.setState(String) calls work without it. Safe to call every frame regardless.
Parameters:
| Name | Description |
|---|---|
elapsed | Seconds since the last frame. |
clear()
Clears all registered states and resets to the empty state, keeping the machine usable.
destroy()
Detaches this machine from its controller and clears all states. Call when the owning sprite is destroyed so the machine does not keep receiving onAnimationFinished callbacks.
getState()
Returns: The current logical state, or "" if FlixelAnimationStateMachine.setState(String) has not run yet.
hasState(String)
Parameters:
| Name | Description |
|---|---|
name | The state name to look up. |
Returns: true if a state with that name is registered.
State
class
org.flixelgdx.animation.FlixelAnimationStateMachine.State
One configurable state in a FlixelAnimationStateMachine, built fluently.
Obtain one from FlixelAnimationStateMachine.addState(String, String) and chain the setters, for example addState("attack", "attack").autoAdvanceTo("idle").onEnter(...).
Methods
loop(boolean)
Sets whether this state's clip loops.
Parameters:
| Name | Description |
|---|---|
loop | true to loop, false to play once. |
Returns: This state, for chaining.
autoAdvanceTo(String)
Makes this state automatically transition to target as soon as its clip finishes. This implies a non-looping clip, so it also sets loop to false. Pair with FlixelAnimationStateMachine.delay(...) to hold the final frame for a moment before advancing.
Parameters:
| Name | Description |
|---|---|
target | The state to enter when this state's clip finishes. |
Returns: This state, for chaining.
delay(float)
Sets how long, in seconds, to wait after this state's clip finishes before auto-advancing. Useful for letting a finished pose linger (for example, holding the last frame of an attack before returning to idle).
This only affects the auto-advance transition, so it does nothing unless FlixelAnimationStateMachine.autoAdvanceTo(...) is also set. The owning machine's FlixelAnimationStateMachine.update(float) must be called each frame for the delay to elapse.
Parameters:
| Name | Description |
|---|---|
seconds | The hold time in seconds; values <= 0 advance immediately. |
Returns: This state, for chaining.
onEnter(Runnable)
Sets an action run when the machine enters this state (after a forced re-entry too).
Parameters:
| Name | Description |
|---|---|
action | The entry action. |
Returns: This state, for chaining.
onExit(Runnable)
Sets an action run when the machine leaves this state for a different one.
Parameters:
| Name | Description |
|---|---|
action | The exit action. |
Returns: This state, for chaining.
allowTo(String...)
Restricts which states may be entered directly from this one. Without any call to this method, every transition out of this state is allowed; once called, only the listed targets are legal. May be called more than once to add more targets.
Parameters:
| Name | Description |
|---|---|
targets | The state names reachable from this state. |
Returns: This state, for chaining.