Skip to content

Commit

Permalink
Add docs & example for SystemParam (bevyengine#1435)
Browse files Browse the repository at this point in the history
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 bevyengine#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
  • Loading branch information
woubuc committed Mar 3, 2021
1 parent b8a0ab0 commit 000dd4c
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ecs/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
19 changes: 19 additions & 0 deletions crates/bevy_ecs/src/system/system_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
}
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 43 additions & 0 deletions examples/ecs/system_param.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 000dd4c

Please sign in to comment.