Skip to main content

FlixelAnimationStateMachine

View source

class

org.flixelgdx.animation.FlixelAnimationStateMachine

public class FlixelAnimationStateMachine implements FlixelDestroyable, FlixelUpdatable

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-advance target, so a one-shot clip (such as an attack) automatically returns to another state the moment it finishes, optionally after a delay,
  • onEnter / onExit hooks for side effects, and
  • the set of legal transitions out 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)

public FlixelAnimationStateMachine(FlixelSprite sprite)

Creates a machine that drives the given sprite's FlixelAnimationController.

Parameters:

NameDescription
spriteThe sprite to animate; its controller is obtained via FlixelSprite.ensureAnimation().

FlixelAnimationStateMachine(FlixelAnimationController)

public FlixelAnimationStateMachine(FlixelAnimationController controller)

Creates a machine that drives the given controller.

Parameters:

NameDescription
controllerThe controller whose registered clips the states refer to.

Fields

onStateChanged

public final FlixelSignal<String> 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)

public State addState(String name)

Registers a logic-only state with no animation clip. Entering it still fires hooks and FlixelAnimationStateMachine.onStateChanged, but plays nothing.

Parameters:

NameDescription
nameThe logical state name.

Returns: The new State for fluent configuration.


addState(String, String)

public State addState(String name, String clipName)

Registers a state that plays clipName (a clip already registered on the controller via addAnimation / addAnimationByPrefix) when entered.

Parameters:

NameDescription
nameThe logical state name.
clipNameThe animation clip to play, or null for a logic-only state.

Returns: The new State for fluent configuration.


removeState(String)

public void removeState(String name)

Removes a registered state. Does not change the current FlixelAnimationStateMachine.getState().

Parameters:

NameDescription
nameThe state to remove.

setState(String)

public boolean setState(String newState)

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:

NameDescription
newStateThe state to enter.

Returns: true if the machine is now in newState, false if the transition was rejected as illegal.


setState(String, boolean)

public boolean setState(String newState, boolean force)

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:

NameDescription
newStateThe state to enter.
forcetrue 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)

public void update(float elapsed)

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:

NameDescription
elapsedSeconds since the last frame.

clear()

public void clear()

Clears all registered states and resets to the empty state, keeping the machine usable.


destroy()

public void 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()

public String getState()

Returns: The current logical state, or "" if FlixelAnimationStateMachine.setState(String) has not run yet.


hasState(String)

public boolean hasState(String name)

Parameters:

NameDescription
nameThe state name to look up.

Returns: true if a state with that name is registered.


State

class

org.flixelgdx.animation.FlixelAnimationStateMachine.State

public static final class 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)

public State loop(boolean loop)

Sets whether this state's clip loops.

Parameters:

NameDescription
looptrue to loop, false to play once.

Returns: This state, for chaining.


autoAdvanceTo(String)

public State autoAdvanceTo(String target)

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:

NameDescription
targetThe state to enter when this state's clip finishes.

Returns: This state, for chaining.


delay(float)

public State delay(float seconds)

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:

NameDescription
secondsThe hold time in seconds; values <= 0 advance immediately.

Returns: This state, for chaining.


onEnter(Runnable)

public State onEnter(Runnable action)

Sets an action run when the machine enters this state (after a forced re-entry too).

Parameters:

NameDescription
actionThe entry action.

Returns: This state, for chaining.


onExit(Runnable)

public State onExit(Runnable action)

Sets an action run when the machine leaves this state for a different one.

Parameters:

NameDescription
actionThe exit action.

Returns: This state, for chaining.


allowTo(String...)

public State allowTo(String... targets)

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:

NameDescription
targetsThe state names reachable from this state.

Returns: This state, for chaining.