-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Merged by Bors] - Add system sets and run criteria example #1909
Changes from 3 commits
33405da
edcb9d6
b02bb4f
b0e909b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
use bevy::{app::AppExit, ecs::schedule::ShouldRun, prelude::*}; | ||
|
||
/// A [SystemLabel] can be applied as a label to systems and system sets, | ||
/// which can then be referred to from other systems. | ||
/// This is useful in case a user wants to e.g. run _before_ or _after_ | ||
/// some label. | ||
/// `Clone`, `Hash`, `Debug`, `PartialEq`, `Eq`, are all required to derive | ||
/// [SystemLabel]. | ||
#[derive(Clone, Hash, Debug, PartialEq, Eq, SystemLabel)] | ||
struct Physics; | ||
|
||
#[derive(Clone, Hash, Debug, PartialEq, Eq, SystemLabel)] | ||
struct PostPhysics; | ||
|
||
/// Resource used to stop our example. | ||
#[derive(Default)] | ||
struct Done(bool); | ||
|
||
/// This is used to show that within a [SystemSet], individual systems can also | ||
/// be labelled, allowing further fine tuning of run ordering. | ||
#[derive(Clone, Hash, Debug, PartialEq, Eq, SystemLabel)] | ||
pub enum PhysicsSystem { | ||
UpdateVelocity, | ||
Movement, | ||
} | ||
|
||
/// This example realizes the following scheme: | ||
/// | ||
/// ```none | ||
/// Physics (Criteria: App has run < 1.0 seconds) | ||
/// \--> update_velocity (via label PhysicsSystem::UpdateVelocity) | ||
/// \--> movement (via label PhysicsSystem::Movement) | ||
/// PostPhysics (Criteria: Resource `done` is false) | ||
/// \--> collision || sfx | ||
/// Exit (Criteria: Resource `done` is true) | ||
/// \--> exit | ||
/// ``` | ||
/// | ||
/// The `Physics` label represents a [SystemSet] containing two systems. | ||
/// This set's criteria is to stop after a second has elapsed. | ||
/// The two systems (update_velocity, movement) runs in a specified order. | ||
/// | ||
/// Another label `PostPhysics` uses run criteria to only run after `Physics` has finished. | ||
/// This set's criteria is to run only when _not done_, as specified via a resource. | ||
/// The two systems here (collision, sfx) are not specified to run in any order, and the actual | ||
/// ordering can then change between invocations. | ||
/// | ||
/// Lastly a system with run criterion _done_ is used to exit the app. | ||
/// ``` | ||
fn main() { | ||
App::build() | ||
.add_plugins(DefaultPlugins) | ||
.init_resource::<Done>() | ||
// Note that the system sets added in this example sets their run criteria explicitly. | ||
// See the `ecs/state.rs` example for a pattern where run criteria are set implicitly for common | ||
// use cases- typically state transitions. | ||
// Also note that a system set has a single run criterion at most, which means using `.with_run_criteria(...)` | ||
// after `SystemSet::on_update(...)` would override the state transition criterion. | ||
.add_system_set( | ||
SystemSet::new() | ||
// This label is added to all systems in this set. | ||
// The label can then be referred to elsewhere (other sets). | ||
.label(Physics) | ||
.with_system( | ||
update_velocity | ||
.system() | ||
// Only applied to the `update_velocity` system | ||
.label(PhysicsSystem::UpdateVelocity), | ||
) | ||
.with_system( | ||
movement | ||
.system() | ||
// Only applied to the `movement` system | ||
.label(PhysicsSystem::Movement) | ||
// Enforce order within this system by specifying this | ||
.after(PhysicsSystem::UpdateVelocity), | ||
) | ||
// This criteria ensures this whole system set only runs when this system's | ||
// output says so (ShouldRun::Yes) | ||
.with_run_criteria(run_for_a_second.system()), | ||
) | ||
.add_system_set( | ||
SystemSet::new() | ||
.label(PostPhysics) | ||
// `collision` and `sfx` are not ordered with respect to | ||
// each other, and may run in any order | ||
.with_system(collision.system()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Small nit: I like to define systems last in system sets as a general pattern. This creates a nice There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok! I'm all for consistency. Updated. |
||
.with_system(sfx.system()) | ||
// This whole set runs after `Physics` (which in this case is a label for | ||
// another set). | ||
// There is also `.before(..)`. | ||
.after(Physics) | ||
// This shows that we can modify existing run criteria results. | ||
// Here we create a _not done_ criteria by piping the output of | ||
// the `is_done` system and inverting the output. | ||
// Notice a string literal also works as a label. | ||
.with_run_criteria(RunCriteria::pipe("is_done_label", inverse.system())), | ||
) | ||
.add_system( | ||
exit.system() | ||
.after(PostPhysics) | ||
// Label the run criteria such that the `PostPhysics` set can reference it | ||
.with_run_criteria(is_done.system().label("is_done_label")), | ||
) | ||
.run(); | ||
} | ||
|
||
/// Example of a run criteria. | ||
/// Here we only want to run for a second, then stop. | ||
fn run_for_a_second(time: Res<Time>, mut done: ResMut<Done>) -> ShouldRun { | ||
let elapsed = time.seconds_since_startup(); | ||
if elapsed < 1.0 { | ||
info!( | ||
"We should run again. Elapsed/remaining: {:.2}s/{:.2}s", | ||
elapsed, | ||
1.0 - elapsed | ||
); | ||
ShouldRun::Yes | ||
} else { | ||
done.0 = true; | ||
ShouldRun::No | ||
} | ||
} | ||
|
||
/// Another run criteria, simply using a resource. | ||
fn is_done(done: Res<Done>) -> ShouldRun { | ||
if done.0 { | ||
ShouldRun::Yes | ||
} else { | ||
ShouldRun::No | ||
} | ||
} | ||
|
||
/// Used with [RunCritera::pipe], inverts the result of the | ||
/// passed system. | ||
fn inverse(input: In<ShouldRun>) -> ShouldRun { | ||
match input.0 { | ||
ShouldRun::No => ShouldRun::Yes, | ||
ShouldRun::Yes => ShouldRun::No, | ||
_ => unreachable!(), | ||
} | ||
} | ||
|
||
fn update_velocity() { | ||
info!("Updating velocity"); | ||
} | ||
|
||
fn movement() { | ||
info!("Updating movement"); | ||
} | ||
|
||
fn collision() { | ||
info!("Physics done- checking collisions"); | ||
} | ||
|
||
fn sfx() { | ||
info!("Physics done- playing some sfx"); | ||
} | ||
|
||
fn exit(mut app_exit_events: EventWriter<AppExit>) { | ||
info!("Exiting..."); | ||
app_exit_events.send(AppExit); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: "Note that the system sets added in this example set their run criteria explicitly."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.