Skip to content

Commit 50bba0f

Browse files
Add example for run conditions (#7652)
Added an example for run conditions. Fixes #7646 if we wait till #7605 is merged and include some of it features.
1 parent b2e1694 commit 50bba0f

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,16 @@ description = "Query for entities that had a specific component removed earlier
936936
category = "ECS (Entity Component System)"
937937
wasm = false
938938

939+
[[example]]
940+
name = "run_conditions"
941+
path = "examples/ecs/run_conditions.rs"
942+
943+
[package.metadata.example.run_conditions]
944+
name = "Run Conditions"
945+
description = "Run systems only when one or multiple conditions are met"
946+
category = "ECS (Entity Component System)"
947+
wasm = false
948+
939949
[[example]]
940950
name = "startup_system"
941951
path = "examples/ecs/startup_system.rs"

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ Example | Description
205205
[Nondeterministic System Order](../examples/ecs/nondeterministic_system_order.rs) | Systems run in paralell, but their order isn't always deteriministic. Here's how to detect and fix this.
206206
[Parallel Query](../examples/ecs/parallel_query.rs) | Illustrates parallel queries with `ParallelIterator`
207207
[Removal Detection](../examples/ecs/removal_detection.rs) | Query for entities that had a specific component removed earlier in the current frame
208+
[Run Conditions](../examples/ecs/run_conditions.rs) | Run systems only when one or multiple conditions are met
208209
[Startup System](../examples/ecs/startup_system.rs) | Demonstrates a startup system (one that runs once when the app starts up)
209210
[State](../examples/ecs/state.rs) | Illustrates how to use States to control transitioning from a Menu state to an InGame state
210211
[System Closure](../examples/ecs/system_closure.rs) | Show how to use closures as systems, and how to configure `Local` variables by capturing external state

examples/ecs/run_conditions.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//! This example demonstrates how to use run conditions to control when systems run.
2+
3+
use bevy::prelude::*;
4+
5+
fn main() {
6+
println!();
7+
println!("For the first 2 seconds you will not be able to increment the counter");
8+
println!("Once that time has passed you can press space, enter, left mouse, right mouse or touch the screen to increment the counter");
9+
println!();
10+
11+
App::new()
12+
.add_plugins(DefaultPlugins)
13+
.init_resource::<InputCounter>()
14+
.add_system(
15+
increment_input_counter
16+
// The common_conditions module has a few useful run conditions
17+
// for checking resources and states. These are included in the prelude.
18+
.run_if(resource_exists::<InputCounter>())
19+
// This is our custom run condition. Both this and the
20+
// above condition must be true for the system to run.
21+
.run_if(has_user_input),
22+
)
23+
.add_system(
24+
print_input_counter
25+
// This is also a custom run condition but this time in the form of a closure.
26+
// This is useful for small, simple run conditions you don't need to reuse.
27+
// All the normal rules still apply: all parameters must be read only except for local parameters.
28+
// In this case we will only run if the input counter resource exists and has changed but not just been added.
29+
.run_if(|res: Option<Res<InputCounter>>| {
30+
if let Some(counter) = res {
31+
counter.is_changed() && !counter.is_added()
32+
} else {
33+
false
34+
}
35+
}),
36+
)
37+
.add_system(
38+
print_time_message
39+
// This function returns a custom run condition, much like the common conditions module.
40+
// It will only return true once 2 seconds have passed.
41+
.run_if(time_passed(2.0))
42+
// You can use the `not` condition from the common_conditions module
43+
// to inverse a run condition. In this case it will return true if
44+
// less than 2.5 seconds have elapsed since the app started.
45+
.run_if(not(time_passed(2.5))),
46+
)
47+
.run();
48+
}
49+
50+
#[derive(Resource, Default)]
51+
struct InputCounter(usize);
52+
53+
/// Return true if any of the defined inputs were just pressed.
54+
/// This is a custom run condition, it can take any normal system parameters as long as
55+
/// they are read only (except for local parameters which can be mutable).
56+
/// It returns a bool which determines if the system should run.
57+
fn has_user_input(
58+
keyboard_input: Res<Input<KeyCode>>,
59+
mouse_button_input: Res<Input<MouseButton>>,
60+
touch_input: Res<Touches>,
61+
) -> bool {
62+
keyboard_input.just_pressed(KeyCode::Space)
63+
|| keyboard_input.just_pressed(KeyCode::Return)
64+
|| mouse_button_input.just_pressed(MouseButton::Left)
65+
|| mouse_button_input.just_pressed(MouseButton::Right)
66+
|| touch_input.any_just_pressed()
67+
}
68+
69+
/// This is a function that returns a closure which can be used as a run condition.
70+
/// This is useful because you can reuse the same run condition but with different variables.
71+
/// This is how the common conditions module works.
72+
fn time_passed(t: f32) -> impl FnMut(Local<f32>, Res<Time>) -> bool {
73+
move |mut timer: Local<f32>, time: Res<Time>| {
74+
// Tick the timer
75+
*timer += time.delta_seconds();
76+
// Return true if the timer has passed the time
77+
*timer >= t
78+
}
79+
}
80+
81+
/// SYSTEM: Increment the input counter
82+
/// Notice how we can take just the `ResMut` and not have to wrap
83+
/// it in an option incase it hasen't been initialized, this is becuase
84+
/// it has a run codition that checks if the `InputCounter` resource exsists
85+
fn increment_input_counter(mut counter: ResMut<InputCounter>) {
86+
counter.0 += 1;
87+
}
88+
89+
/// SYSTEM: Print the input counter
90+
fn print_input_counter(counter: Res<InputCounter>) {
91+
println!("Input counter: {}", counter.0);
92+
}
93+
94+
/// SYSTEM: Adds the input counter resource
95+
fn print_time_message() {
96+
println!("It has been more than 2 seconds since the program started and less than 2.5 seconds");
97+
}

0 commit comments

Comments
 (0)