//! This example illustrates how to use [`States`] for high-level app control flow. //! States are a powerful but intuitive tool for controlling which logic runs when. //! You can have multiple independent states, and the [`OnEnter`] and [`OnExit`] schedules //! can be used to great effect to ensure that you handle setup and teardown appropriately. //! //! In this case, we're transitioning from a `Menu` state to an `InGame` state. use bevy::{dev_tools::states::*, prelude::*}; fn main() { App::new() .add_plugins(DefaultPlugins) .init_state::() // Alternatively we could use .insert_state(AppState::Menu) .add_systems(Startup, setup) // This system runs when we enter `AppState::Menu`, during the `StateTransition` schedule. // All systems from the exit schedule of the state we're leaving are run first, // and then all systems from the enter schedule of the state we're entering are run second. .add_systems(OnEnter(AppState::Menu), setup_menu) // By contrast, update systems are stored in the `Update` schedule. They simply // check the value of the `State` resource to see if they should run each frame. .add_systems(Update, menu.run_if(in_state(AppState::Menu))) .add_systems(OnExit(AppState::Menu), cleanup_menu) .add_systems(OnEnter(AppState::InGame), setup_game) .add_systems( Update, (movement, change_color).run_if(in_state(AppState::InGame)), ) .add_systems(Update, log_transitions::) .run(); } #[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)] enum AppState { #[default] Menu, InGame, } #[derive(Resource)] struct MenuData { button_entity: Entity, } const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15); const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25); const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35); fn setup(mut commands: Commands) { commands.spawn(Camera2d); } fn setup_menu(mut commands: Commands) { let button_entity = commands .spawn(NodeBundle { style: Style { // center button width: Val::Percent(100.), height: Val::Percent(100.), justify_content: JustifyContent::Center, align_items: AlignItems::Center, ..default() }, ..default() }) .with_children(|parent| { parent .spawn(ButtonBundle { style: Style { width: Val::Px(150.), height: Val::Px(65.), // horizontally center child text justify_content: JustifyContent::Center, // vertically center child text align_items: AlignItems::Center, ..default() }, background_color: NORMAL_BUTTON.into(), ..default() }) .with_children(|parent| { parent.spawn(TextBundle::from_section( "Play", TextStyle { font_size: 33.0, color: Color::srgb(0.9, 0.9, 0.9), ..default() }, )); }); }) .id(); commands.insert_resource(MenuData { button_entity }); } fn menu( mut next_state: ResMut>, mut interaction_query: Query< (&Interaction, &mut BackgroundColor), (Changed, With