diff --git a/Cargo.toml b/Cargo.toml index 0b1427689d..359b3ee263 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -882,6 +882,16 @@ description = "Full guide to Bevy's ECS" category = "ECS (Entity Component System)" wasm = false +[[example]] +name = "apply_system_buffers" +path = "examples/ecs/apply_system_buffers.rs" + +[package.metadata.example.apply_system_buffers] +name = "Apply System Buffers" +description = "Show how to use `apply_system_buffers` system" +category = "ECS (Entity Component System)" +wasm = false + [[example]] name = "component_change_detection" path = "examples/ecs/component_change_detection.rs" diff --git a/examples/README.md b/examples/README.md index c54ca491ec..41eaddbc0b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -197,6 +197,7 @@ Example | Description Example | Description --- | --- +[Apply System Buffers](../examples/ecs/apply_system_buffers.rs) | Show how to use `apply_system_buffers` system [Component Change Detection](../examples/ecs/component_change_detection.rs) | Change detection on components [Custom Query Parameters](../examples/ecs/custom_query_param.rs) | Groups commonly used compound queries and query filters into a single type [ECS Guide](../examples/ecs/ecs_guide.rs) | Full guide to Bevy's ECS diff --git a/examples/ecs/apply_system_buffers.rs b/examples/ecs/apply_system_buffers.rs new file mode 100644 index 0000000000..67a25274dd --- /dev/null +++ b/examples/ecs/apply_system_buffers.rs @@ -0,0 +1,170 @@ +//! This example illustrates how to use the `apply_system_buffers` system +//! to flush commands added by systems that have already run, +//! but have not had their buffers applied yet. +//! +//! This is useful when you don't want to wait until the next flush set +//! automatically added by Bevy (usually `CoreSet::UpdateFlush`, for systems +//! added to `CoreSet::Update`) but want to flush commands immediately. +//! +//! It is important that systems are ordered correctly with respect to +//! `apply_system_buffers`, to avoid surprising non-deterministic system execution order. + +use bevy::prelude::*; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .init_resource::() + .add_startup_system(setup) + .add_system(despawn_old_and_spawn_new_fruits.before(CustomFlush)) + .add_system(apply_system_buffers.in_set(CustomFlush)) + .add_system(count_apple.after(CustomFlush)) + .add_system(count_orange) + .add_system(bevy::window::close_on_esc) + .run(); +} + +#[derive(Resource)] +struct Timers { + repeating: Timer, +} + +impl Default for Timers { + fn default() -> Self { + Self { + repeating: Timer::from_seconds(0.5, TimerMode::Repeating), + } + } +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] +struct CustomFlush; + +#[derive(Component)] +struct Apple; + +#[derive(Component)] +struct Orange; + +#[derive(Component)] +struct AppleCount; + +#[derive(Component)] +struct OrangeCount; + +// Setup the counters in the UI. +fn setup(mut commands: Commands, asset_server: Res) { + commands.spawn(Camera2dBundle::default()); + + commands + .spawn(NodeBundle { + style: Style { + size: Size::new(Val::Percent(100.0), Val::Percent(100.0)), + align_items: AlignItems::Center, + justify_content: JustifyContent::Center, + flex_direction: FlexDirection::Column, + ..default() + }, + ..default() + }) + .with_children(|parent| { + parent.spawn(( + TextBundle::from_section( + "Apple: nothing counted yet".to_string(), + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 80.0, + color: Color::ORANGE, + }, + ), + AppleCount, + )); + parent.spawn(( + TextBundle::from_section( + "Orange: nothing counted yet".to_string(), + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 80.0, + color: Color::ORANGE, + }, + ), + OrangeCount, + )); + }); +} + +// Every tick, before the CustomFlush we added, we despawn any Apple and Orange +// we have previously spawned, if any. Then we tick the timer, and if the timer +// has finished during this tick, we spawn a new Apple and a new Orange. +// +// The commands that we have added here will normally be flushed by Bevy +// as part of the `CoreSet::UpdateFlush` set, but because we have ordered +// this system to run before `apply_system_buffer.in_set(CustomFlush)`, +// these commands added here will be flushed during our custom flush. +fn despawn_old_and_spawn_new_fruits( + mut commands: Commands, + time: Res