From 0f4ca62a6abc9eb8de4c225249cd84afe4a4e8b4 Mon Sep 17 00:00:00 2001 From: B-Janson Date: Fri, 14 Jan 2022 19:29:10 +0000 Subject: [PATCH] Add generic systems example (#2636) # Objective My attempt at fixing #2142. My very first attempt at contributing to Bevy so more than open to any feedback. I borrowed heavily from the [Bevy Cheatbook page](https://bevy-cheatbook.github.io/patterns/generic-systems.html?highlight=generic#generic-systems). ## Solution Fairly straightforward example using a clean up system to delete entities that are coupled with app state after exiting that state. Co-authored-by: B-Janson --- Cargo.toml | 4 ++ examples/README.md | 1 + examples/ecs/generic_system.rs | 84 ++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 examples/ecs/generic_system.rs diff --git a/Cargo.toml b/Cargo.toml index c451e83f06f57..c01bcc621db82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -310,6 +310,10 @@ path = "examples/ecs/event.rs" name = "fixed_timestep" path = "examples/ecs/fixed_timestep.rs" +[[example]] +name = "generic_system" +path = "examples/ecs/generic_system.rs" + [[example]] name = "hierarchy" path = "examples/ecs/hierarchy.rs" diff --git a/examples/README.md b/examples/README.md index 02a10eabb4062..608b811688856 100644 --- a/examples/README.md +++ b/examples/README.md @@ -165,6 +165,7 @@ Example | File | Description `component_change_detection` | [`ecs/component_change_detection.rs`](./ecs/component_change_detection.rs) | Change detection on components `event` | [`ecs/event.rs`](./ecs/event.rs) | Illustrates event creation, activation, and reception `fixed_timestep` | [`ecs/fixed_timestep.rs`](./ecs/fixed_timestep.rs) | Shows how to create systems that run every fixed timestep, rather than every tick +`generic_system` | [`ecs/generic_system.rs`](./ecs/generic_system.rs) | Shows how to create systems that can be reused with different types `hierarchy` | [`ecs/hierarchy.rs`](./ecs/hierarchy.rs) | Creates a hierarchy of parents and children entities `iter_combinations` | [`ecs/iter_combinations.rs`](./ecs/iter_combinations.rs) | Shows how to iterate over combinations of query results. `parallel_query` | [`ecs/parallel_query.rs`](./ecs/parallel_query.rs) | Illustrates parallel queries with `ParallelIterator` diff --git a/examples/ecs/generic_system.rs b/examples/ecs/generic_system.rs new file mode 100644 index 0000000000000..610a3e8a1f020 --- /dev/null +++ b/examples/ecs/generic_system.rs @@ -0,0 +1,84 @@ +use bevy::{ecs::component::Component, prelude::*}; + +/// Generic types allow us to reuse logic across many related systems, +/// allowing us to specialize our function's behavior based on which type (or types) are passed in. +/// +/// This is commonly useful for working on related components or resources, +/// where we want to have unique types for querying purposes but want them all to work the same way. +/// This is particularly powerful when combined with user-defined traits to add more functionality to these related types. +/// Remember to insert a specialized copy of the system into the schedule for each type that you want to operate on! +/// +/// For more advice on working with generic types in Rust, check out https://doc.rust-lang.org/book/ch10-01-syntax.html +/// or https://doc.rust-lang.org/rust-by-example/generics.html + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +enum AppState { + MainMenu, + InGame, +} + +struct TextToPrint(String); + +struct MenuClose; +struct LevelUnload; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_state(AppState::MainMenu) + .add_startup_system(setup_system) + .add_system(print_text_system) + .add_system_set( + SystemSet::on_update(AppState::MainMenu).with_system(transition_to_in_game_system), + ) + // add the cleanup systems + .add_system_set( + // Pass in the types your system should operate on using the :: (turbofish) syntax + SystemSet::on_exit(AppState::MainMenu).with_system(cleanup_system::), + ) + .add_system_set( + SystemSet::on_exit(AppState::InGame).with_system(cleanup_system::), + ) + .run(); +} + +fn setup_system(mut commands: Commands) { + commands + .spawn() + .insert(Timer::from_seconds(1.0, true)) + .insert(TextToPrint( + "I will print until you press space.".to_string(), + )) + .insert(MenuClose); + + commands + .spawn() + .insert(Timer::from_seconds(1.0, true)) + .insert(TextToPrint("I will always print".to_string())) + .insert(LevelUnload); +} + +fn print_text_system(time: Res