use bevy::prelude::*;
use bevy_fsm::{EnumEvent, FSMState, FSMTransition, fsm_observer, Enter, Exit, FSMPlugin, StateChangeRequest};
fn main() {
let mut app = App::new();
app.add_plugins(MinimalPlugins)
.add_plugins(FSMPlugin::<GameState>::default());
fsm_observer!(app, GameState, on_enter_playing);
fsm_observer!(app, GameState, on_exit_playing);
app.add_systems(Startup, setup)
.add_systems(Update, cycle_states)
.run();
}
#[derive(
Component, EnumEvent, FSMTransition, FSMState, Reflect, Clone, Copy, Debug, PartialEq, Eq, Hash,
)]
#[reflect(Component)]
enum GameState {
MainMenu,
Playing,
Paused,
GameOver,
}
fn setup(mut commands: Commands) {
println!("=== Fully Connected FSM Example ===");
println!("This FSM allows ALL transitions (fully connected graph)");
println!("Observers registered using fsm_observer! macro\n");
commands.spawn((GameState::MainMenu, Name::new("Game")));
}
fn cycle_states(
mut commands: Commands,
query: Query<(Entity, &GameState, &Name)>,
mut frame: Local<u32>,
) {
*frame += 1;
for (entity, &state, name) in query.iter() {
let next_state = match *frame {
1 => Some(GameState::Playing),
2 => Some(GameState::Paused),
3 => Some(GameState::Playing),
4 => Some(GameState::GameOver),
5 => {
println!("\nDemonstrating fully connected graph:");
println!(" GameOver -> MainMenu ✓ (would be blocked in a typical FSM)");
Some(GameState::MainMenu)
}
6 => {
println!(" MainMenu -> GameOver ✓ (skipping intermediate states)");
Some(GameState::GameOver)
}
7 => {
println!(" GameOver -> Playing ✓ (any transition is valid!)\n");
Some(GameState::Playing)
}
8 => {
println!("=== Example complete! ===");
std::process::exit(0);
}
_ => None,
};
if let Some(next) = next_state {
if *frame < 50 {
println!("{} transitioning: {:?} -> {:?}", name, state, next);
}
commands.trigger(StateChangeRequest { entity, next });
}
}
}
fn on_enter_playing(_trigger: On<Enter<game_state::Playing>>) {
println!(" [ENTER Playing] Game started!");
}
fn on_exit_playing(_trigger: On<Exit<game_state::Playing>>) {
println!(" [EXIT Playing] Game stopped!");
}