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!("=== Simple FSM Example ===");
println!("This FSM allows ALL transitions by default");
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)>,
time: Res<Time>,
mut elapsed: Local<f32>,
mut last_transition: Local<u32>,
) {
*elapsed += time.delta_secs();
let current_step = (*elapsed * 2.0) as u32;
if current_step != *last_transition {
*last_transition = current_step;
for (entity, &state, name) in query.iter() {
let next_state = match current_step {
2 => Some(GameState::Playing),
4 => Some(GameState::Paused),
6 => Some(GameState::Playing),
8 => Some(GameState::GameOver),
10 => Some(GameState::MainMenu), 12 => {
println!("\n=== Example complete! ===");
std::process::exit(0);
}
_ => None,
};
if let Some(next) = next_state {
println!("\n{} 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!");
}