Create reusable run conditions
Bevy version: 0.14Last updated:
Create a function that returns an impl Condition<()>
type and then use the built-in Bevy run conditions from your function:
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, States)]
enum AppState {
#[default]
MainMenu,
InGame,
Paused,
}
#[derive(Resource)]
struct Score(i32);
fn game_ready() -> impl ReadOnlySystem<In = (), Out = bool> {
in_state(AppState::MainMenu).and_then(in_state(AppState::InGame))
}
// Condition can be used as a more succinct type
fn score_ready() -> impl Condition<()> {
resource_exists::<Score>.and_then(game_ready())
}
This lets us use Bevy's built in run conditions outside of our App
definitions.
Bevy's common run conditions like resource_exists::<T>
and in_state
are part of the bevy::ecs::schedule::common_conditions
.
On the Bevy example on run conditions we can see a somewhat complicated example that chains run conditions together:
#[derive(Resource, Default)]
struct InputCounter(u32);
fn increment_input_counter(mut input_counter: ResMut<InputCounter>) {
input_counter.0 += 1;
}
fn has_user_input(input_counter: Res<InputCounter>) -> bool {
input_counter.0 > 0
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_resource::<InputCounter>()
.add_systems(
Update,
increment_input_counter
.run_if(resource_exists::<InputCounter>.or_else(has_user_input)),
)
.run();
}
But extracting these run conditions into a function allows us to write more declarative app definitions that better express the logic of when these systems should run.
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_resource::<Score>()
.add_systems(
Update,
(
countdown_game_timer.run_if(game_ready()),
update_scoreboard.run_if(score_ready()),
),
)
.run();
}