flame_state_machine 1.1.0
flame_state_machine: ^1.1.0 copied to clipboard
A lightweight, type-safe state machine for the Flame game engine, enabling modular and reusable behavior for Flame components.
flame_state_machine #
A lightweight and flexible finite state machine package for the Flame game engine, written in Dart.
Manage complex stateful behaviors for your Flame Components with ease, enabling clean and maintainable game logic.
Features #
- Generic state machine designed to work seamlessly with Flame
Components - Supports prioritized state transitions with custom guard conditions
- Easy registration of reversible transitions
- Lifecycle callbacks for entering, exiting, and updating states
AnyStatesupport for transitions valid from any current state
Usage #
1. Create states #
Extend the State<T> class to define your custom states:
class IdleState extends State<Enemy> {
@override
void onEnter(Enemy enemy, [State<Enemy>? from]) {
print('Enemy entered Idle state');
}
@override
void onExit(Enemy enemy, [State<Enemy>? to]) {
print('Enemy exited Idle state');
}
@override
void onUpdate(double dt, Enemy enemy) {
// handle idle behavior
}
}
2. Setup state machine in your Flame component #
Mix in HasStates and provide a StateMachine instance:
class Enemy extends PositionComponent with HasStates<Enemy> {
late final StateMachine<Enemy> stateMachine;
Enemy() {
final idleState = IdleState();
final runningState = RunningState();
final deathState = DeathState();
stateMachine = StateMachine<Enemy>(
owner: this,
initialState: idleState,
);
stateMachine.register(
to: deathState,
guard: (enemy) => !enemy.isAlive,
priority: 100,
);
stateMachine.register(
from: idleState,
to: runningState,
guard: (enemy) => enemy.isMoving,
reverse: true,
);
}
@override
void update(double dt) {
super.update(dt);
// stateMachine.update(dt); // called automatically by HasStates
}
}
3. Register transitions with guards #
Use register() to define valid state changes and their conditions:
stateMachine.register(
priority: 1, // transitions with higher priority values will be checked first
from: IdleState(), // if not provided the transition can occur from any state
to: RunningState(),
guard: (enemy) => enemy.isMoving,
reverse: true, // automatically registers reverse transition
reversePriority: 1, // priority for the reverse transition
reverseGuard: (enemy) => !enemy.isMoving, // guard for the reverse transition (Constructed automatically if not provided)
);
Or use addTransition() to add a StateTransition Object manually:
stateMachine.addTransition(
StateTransition(
from: IdleState(),
to: RunningState(),
guard: (enemy) => enemy.isMoving,
)
);
Note
If you use addTransition(), you must define the reverse transition yourself, like so:
stateMachine.addTransition(
StateTransition(
from: RunningState(),
to: IdleState(),
guard: (enemy) => !enemy.isMoving,
)
);
API #
StateMachine<T>— Core FSM logicState<T>— Base class for your states (overrideonEnter,onExit,onUpdate)StateTransition<T>— Defines transitions between states with guards and prioritiesHasStates<T extends Component>— Mixin for Flame components to attach a state machine
Contributing #
Contributions and suggestions are welcome! Feel free to open issues or submit pull requests.