From 000dd4c1c2a7c707ea059243e836301e45a5276a Mon Sep 17 00:00:00 2001 From: Wouter Buckens Date: Wed, 3 Mar 2021 03:11:11 +0000 Subject: [PATCH] Add docs & example for SystemParam (#1435) It took me a little while to figure out how to use the `SystemParam` derive macro to easily create my own params. So I figured I'd add some docs and an example with what I learned. - Fixed a bug in the `SystemParam` derive macro where it didn't detect the correct crate name when used in an example (no longer relevant, replaced by #1426 - see further) - Added some doc comments and a short example code block in the docs for the `SystemParam` trait - Added a more complete example with explanatory comments in examples --- Cargo.toml | 4 ++ crates/bevy_ecs/macros/src/lib.rs | 1 + crates/bevy_ecs/src/system/system_param.rs | 19 ++++++++++ examples/README.md | 1 + examples/ecs/system_param.rs | 43 ++++++++++++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 examples/ecs/system_param.rs diff --git a/Cargo.toml b/Cargo.toml index 719723e12d..1fc03d2ce9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -260,6 +260,10 @@ path = "examples/ecs/state.rs" name = "system_chaining" path = "examples/ecs/system_chaining.rs" +[[example]] +name = "system_param" +path = "examples/ecs/system_param.rs" + [[example]] name = "timers" path = "examples/ecs/timers.rs" diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index f9066c6815..c3fe34e6ea 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -338,6 +338,7 @@ struct SystemParamFieldAttributes { static SYSTEM_PARAM_ATTRIBUTE_NAME: &str = "system_param"; +/// Implement `SystemParam` to use a struct as a parameter in a system #[proc_macro_derive(SystemParam, attributes(system_param))] pub fn derive_system_param(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 01ed94a3de..233b0c9133 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -5,6 +5,25 @@ use crate::{ }; use parking_lot::Mutex; use std::{any::TypeId, marker::PhantomData, sync::Arc}; + +/// A parameter that can be used in a system function +/// +/// # Derive +/// This trait can be derived. +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// use bevy_ecs::SystemParam; +/// +/// #[derive(SystemParam)] +/// pub struct MyParam<'a> { +/// foo: Res<'a, usize>, +/// } +/// +/// fn my_system(param: MyParam) { +/// // Access the resource through `param.foo` +/// } +/// ``` pub trait SystemParam: Sized { type Fetch: for<'a> FetchSystemParam<'a>; } diff --git a/examples/README.md b/examples/README.md index 6d0545cde7..a79338884a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -135,6 +135,7 @@ Example | File | Description `startup_system` | [`ecs/startup_system.rs`](./ecs/startup_system.rs) | Demonstrates a startup system (one that runs once when the app starts up) `state` | [`ecs/state.rs`](./ecs/state.rs) | Illustrates how to use States to control transitioning from a Menu state to an InGame state `system_chaining` | [`ecs/system_chaining.rs`](./ecs/system_chaining.rs) | Chain two systems together, specifying a return type in a system (such as `Result`) +`system_param` | [`ecs/system_param.rs`](./ecs/system_param.rs) | Illustrates creating custom system parameters with `SystemParam` `timers` | [`ecs/timers.rs`](./ecs/timers.rs) | Illustrates ticking `Timer` resources inside systems and handling their state ## Games diff --git a/examples/ecs/system_param.rs b/examples/ecs/system_param.rs new file mode 100644 index 0000000000..da69d25742 --- /dev/null +++ b/examples/ecs/system_param.rs @@ -0,0 +1,43 @@ +use bevy::{ecs::SystemParam, prelude::*}; + +/// This example creates a SystemParam struct that counts the number of players +fn main() { + App::build() + .insert_resource(PlayerCount(0)) + .add_startup_system(spawn.system()) + .add_system(count_players.system()) + .run(); +} + +struct Player; +struct PlayerCount(usize); + +/// The SystemParam struct can contain any types that can also be included in a +/// system function signature. +/// +/// In this example, it includes a query and a mutable resource. +#[derive(SystemParam)] +pub struct PlayerCounter<'a> { + players: Query<'a, &'a Player>, + count: ResMut<'a, PlayerCount>, +} + +impl<'a> PlayerCounter<'a> { + fn count(&mut self) { + self.count.0 = self.players.iter().len(); + } +} + +/// Spawn some players to count +fn spawn(commands: &mut Commands) { + commands.spawn((Player,)); + commands.spawn((Player,)); + commands.spawn((Player,)); +} + +/// The SystemParam can be used directly in a system argument. +fn count_players(mut counter: PlayerCounter) { + counter.count(); + + println!("{} players in the game", counter.count.0); +}