diff --git a/Cargo.toml b/Cargo.toml index ccf0126d39f95..4c417d9eb70af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1352,17 +1352,6 @@ description = "Illustrates how to use States to control transitioning from a Men category = "ECS (Entity Component System)" wasm = false -[[example]] -name = "advanced_state" -path = "examples/ecs/advanced_state.rs" -doc-scrape-examples = true - -[package.metadata.example.advanced_state] -name = "Advanced State" -description = "Illustrates use of some of the more advanced state concepts, such as `StateMatchers`." -category = "ECS (Entity Component System)" -wasm = false - [[example]] name = "system_piping" path = "examples/ecs/system_piping.rs" diff --git a/examples/README.md b/examples/README.md index 9223a878a5f6f..4aec9498546ba 100644 --- a/examples/README.md +++ b/examples/README.md @@ -213,7 +213,6 @@ Example | Description Example | Description --- | --- -[Advanced State](../examples/ecs/advanced_state.rs) | Illustrates use of some of the more advanced state concepts, such as `StateMatchers`. [Apply System Buffers](../examples/ecs/apply_deferred.rs) | Show how to use `apply_deferred` system [Component Change Detection](../examples/ecs/component_change_detection.rs) | Change detection on components [Custom Query Parameters](../examples/ecs/custom_query_param.rs) | Groups commonly used compound queries and query filters into a single type diff --git a/examples/ecs/advanced_state.rs b/examples/ecs/advanced_state.rs deleted file mode 100644 index 1135f762ef987..0000000000000 --- a/examples/ecs/advanced_state.rs +++ /dev/null @@ -1,347 +0,0 @@ -//! This example illustrates how to use some of the more advanced [`States`] functionality for high-level app control flow. -//! -//! The use case here is identical to the regular [state](./state.rs) example, but we will be -//! utilizing the `StateMatcher` trait more directly. -use bevy::prelude::*; - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_state::() - .add_systems(Startup, setup) - // When we check whether a state is valid, we use a `StateMatcher`. - // In the simple example, we use pattern matching to generate one on the fly - // But we can also use pre-defined ones, like `ShowsUI` - .add_systems(on_exit_strict!(ShowsUI), cleanup_ui) - // In addition, all `States` also implement `StateMatcher`, so you can use them here. - // Although there are some optimizations around `OnEnter(S)` and `OnExit(S)` that make - // those a better choice in this case. - .add_systems(on_enter!(AppState::Menu), setup_menu) - // A state matcher can even be an enum! or really anything with that implements - // the state matcher trait (see below). - .add_systems(on_enter!(InGame::Paused), setup_paused) - .add_systems(on_enter!(InGame::Running), setup_in_game_ui) - // And unlike a regular state, the values are not mutually exclusive. - // So this will be valid both when the game is paused and when it's not - .add_systems(on_enter!(InGame::Any), setup_game) - // And all the same things apply with the `in_state!` macro - .add_systems(Update, menu.run_if(in_state!(AppState::Menu))) - .add_systems(Update, change_color.run_if(in_state!(InGame::Any))) - .add_systems(Update, toggle_pause) - // And it still works with conditional states as well - .add_sub_state::(InGame::Running) - .add_systems(Update, invert_movement.run_if(in_state!(MovementState, _))) - .add_systems(Update, movement.run_if(in_state(MovementState::Normal))) - .add_systems( - Update, - inverted_movement.run_if(in_state(MovementState::Inverted)), - ) - .run(); -} - -// The simplest way to define a state matcher is using the `state_matcher!` macro. -// You pass in the visibility (optionally), name, state type and match expression. -state_matcher!(pub ShowsUI, AppState, Menu | InGame { .. } ); - -#[derive(Debug, Eq, PartialEq, Hash, Clone)] -enum InGame { - Any, - Running, - Paused, -} - -// State Matchers can also be implemented manually -// This allows for somewhat more complex situations, -// For example here we can determine if we want to match in -// any InGame state, only when the game is paused, or only when it -// is running. You can't have this kind of logic using pure equality, -// and having it defined this way makes it re-usable and customizable to your needs. -impl StateMatcher for InGame { - fn match_state(&self, state: &AppState) -> bool { - match state { - AppState::InGame { paused } => match self { - InGame::Any => true, - InGame::Running => !*paused, - InGame::Paused => *paused, - }, - _ => false, - } - } -} - -#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)] -enum AppState { - #[default] - Menu, - InGame { - paused: bool, - }, -} - -#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)] -enum MovementState { - #[default] - Normal, - Inverted, -} - -const NORMAL_BUTTON: Color = Color::rgb(0.15, 0.15, 0.15); -const HOVERED_BUTTON: Color = Color::rgb(0.25, 0.25, 0.25); -const PRESSED_BUTTON: Color = Color::rgb(0.35, 0.75, 0.35); -const LABEL: Color = Color::rgba(0.0, 0.0, 0.0, 0.7); - -fn setup(mut commands: Commands) { - commands.spawn(Camera2dBundle::default()); -} - -fn setup_menu(mut commands: Commands) { - 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: 40.0, - color: Color::rgb(0.9, 0.9, 0.9), - ..default() - }, - )); - }); - }); -} - -fn menu( - mut next_state: ResMut>, - mut interaction_query: Query< - (&Interaction, &mut BackgroundColor), - (Changed, With