bevy/examples/ecs/one_shot_systems.rs

60 lines
1.8 KiB
Rust
Raw Normal View History

One Shot Systems (#8963) I'm adopting this ~~child~~ PR. # Objective - Working with exclusive world access is not always easy: in many cases, a standard system or three is more ergonomic to write, and more modularly maintainable. - For small, one-off tasks (commonly handled with scripting), running an event-reader system incurs a small but flat overhead cost and muddies the schedule. - Certain forms of logic (e.g. turn-based games) want very fine-grained linear and/or branching control over logic. - SystemState is not automatically cached, and so performance can suffer and change detection breaks. - Fixes https://github.com/bevyengine/bevy/issues/2192. - Partial workaround for https://github.com/bevyengine/bevy/issues/279. ## Solution - Adds a SystemRegistry resource to the World, which stores initialized systems keyed by their SystemSet. - Allows users to call world.run_system(my_system) and commands.run_system(my_system), without re-initializing or losing state (essential for change detection). - Add a Callback type to enable convenient use of dynamic one shot systems and reduce the mental overhead of working with Box<dyn SystemSet>. - Allow users to run systems based on their SystemSet, enabling more complex user-made abstractions. ## Future work - Parameterized one-shot systems would improve reusability and bring them closer to events and commands. The API could be something like run_system_with_input(my_system, my_input) and use the In SystemParam. - We should evaluate the unification of commands and one-shot systems since they are two different ways to run logic on demand over a World. ### Prior attempts - https://github.com/bevyengine/bevy/pull/2234 - https://github.com/bevyengine/bevy/pull/2417 - https://github.com/bevyengine/bevy/pull/4090 - https://github.com/bevyengine/bevy/pull/7999 This PR continues the work done in https://github.com/bevyengine/bevy/pull/7999. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Federico Rinaldi <gisquerin@gmail.com> Co-authored-by: MinerSebas <66798382+MinerSebas@users.noreply.github.com> Co-authored-by: Aevyrie <aevyrie@gmail.com> Co-authored-by: Alejandro Pascual Pozo <alejandro.pascual.pozo@gmail.com> Co-authored-by: Rob Parrett <robparrett@gmail.com> Co-authored-by: François <mockersf@gmail.com> Co-authored-by: Dmytro Banin <banind@cs.washington.edu> Co-authored-by: James Liu <contact@jamessliu.com>
2023-09-19 20:17:05 +00:00
//! Demonstrates the use of "one-shot systems", which run once when triggered.
//!
//! These can be useful to help structure your logic in a push-based fashion,
//! reducing the overhead of running extremely rarely run systems
//! and improving schedule flexibility.
//!
//! See the [`World::run_system`](World::run_system) or
//! [`World::run_system_once`](World#method.run_system_once_with)
Fix intra-doc link warnings (#10445) When `cargo doc -Zunstable-options -Zrustdoc-scrape-examples` (trying to figure out why it doesn't work with bevy), I had the following warnings: ``` warning: unresolved link to `Quad` --> examples/2d/mesh2d.rs:1:66 | 1 | //! Shows how to render a polygonal [`Mesh`], generated from a [`Quad`] primitive, in a 2D scene. | ^^^^ no item named `Quad` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default warning: `bevy` (example "mesh2d") generated 1 warning warning: unresolved link to `update_weights` --> examples/animation/morph_targets.rs:6:17 | 6 | //! See the [`update_weights`] system for details. | ^^^^^^^^^^^^^^ no item named `update_weights` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default warning: public documentation for `morph_targets` links to private item `name_morphs` --> examples/animation/morph_targets.rs:7:43 | 7 | //! - How to read morph target names in [`name_morphs`]. | ^^^^^^^^^^^ this item is private | = note: this link will resolve properly if you pass `--document-private-items` = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default warning: public documentation for `morph_targets` links to private item `setup_animations` --> examples/animation/morph_targets.rs:8:48 | 8 | //! - How to play morph target animations in [`setup_animations`]. | ^^^^^^^^^^^^^^^^ this item is private | = note: this link will resolve properly if you pass `--document-private-items` warning: `bevy` (example "morph_targets") generated 3 warnings warning: unresolved link to `Quad` --> examples/2d/mesh2d_vertex_color_texture.rs:1:66 | 1 | //! Shows how to render a polygonal [`Mesh`], generated from a [`Quad`] primitive, in a 2D scene. | ^^^^ no item named `Quad` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default warning: `bevy` (example "mesh2d_vertex_color_texture") generated 1 warning warning: unresolved link to `UIScale` --> examples/ui/ui_scaling.rs:1:36 | 1 | //! This example illustrates the [`UIScale`] resource from `bevy_ui`. | ^^^^^^^ no item named `UIScale` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default warning: `bevy` (example "ui_scaling") generated 1 warning warning: unresolved link to `dependencies` --> examples/app/headless.rs:5:6 | 5 | //! [dependencies] | ^^^^^^^^^^^^ no item named `dependencies` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default warning: `bevy` (example "headless") generated 1 warning warning: unresolved link to `Material2d` --> examples/2d/mesh2d_manual.rs:3:26 | 3 | //! It doesn't use the [`Material2d`] abstraction, but changes the vertex buffer to include verte... | ^^^^^^^^^^ no item named `Material2d` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default warning: `bevy` (example "mesh2d_manual") generated 1 warning ```
2023-11-08 14:33:46 +00:00
//! docs for more details.
One Shot Systems (#8963) I'm adopting this ~~child~~ PR. # Objective - Working with exclusive world access is not always easy: in many cases, a standard system or three is more ergonomic to write, and more modularly maintainable. - For small, one-off tasks (commonly handled with scripting), running an event-reader system incurs a small but flat overhead cost and muddies the schedule. - Certain forms of logic (e.g. turn-based games) want very fine-grained linear and/or branching control over logic. - SystemState is not automatically cached, and so performance can suffer and change detection breaks. - Fixes https://github.com/bevyengine/bevy/issues/2192. - Partial workaround for https://github.com/bevyengine/bevy/issues/279. ## Solution - Adds a SystemRegistry resource to the World, which stores initialized systems keyed by their SystemSet. - Allows users to call world.run_system(my_system) and commands.run_system(my_system), without re-initializing or losing state (essential for change detection). - Add a Callback type to enable convenient use of dynamic one shot systems and reduce the mental overhead of working with Box<dyn SystemSet>. - Allow users to run systems based on their SystemSet, enabling more complex user-made abstractions. ## Future work - Parameterized one-shot systems would improve reusability and bring them closer to events and commands. The API could be something like run_system_with_input(my_system, my_input) and use the In SystemParam. - We should evaluate the unification of commands and one-shot systems since they are two different ways to run logic on demand over a World. ### Prior attempts - https://github.com/bevyengine/bevy/pull/2234 - https://github.com/bevyengine/bevy/pull/2417 - https://github.com/bevyengine/bevy/pull/4090 - https://github.com/bevyengine/bevy/pull/7999 This PR continues the work done in https://github.com/bevyengine/bevy/pull/7999. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Federico Rinaldi <gisquerin@gmail.com> Co-authored-by: MinerSebas <66798382+MinerSebas@users.noreply.github.com> Co-authored-by: Aevyrie <aevyrie@gmail.com> Co-authored-by: Alejandro Pascual Pozo <alejandro.pascual.pozo@gmail.com> Co-authored-by: Rob Parrett <robparrett@gmail.com> Co-authored-by: François <mockersf@gmail.com> Co-authored-by: Dmytro Banin <banind@cs.washington.edu> Co-authored-by: James Liu <contact@jamessliu.com>
2023-09-19 20:17:05 +00:00
use bevy::{
ecs::system::{RunSystemOnce, SystemId},
prelude::*,
};
fn main() {
App::new()
.add_systems(Startup, (count_entities, setup))
.add_systems(PostUpdate, count_entities)
.add_systems(Update, evaluate_callbacks)
.run();
}
// Any ordinary system can be run via commands.run_system or world.run_system.
fn count_entities(all_entities: Query<()>) {
dbg!(all_entities.iter().count());
}
#[derive(Component)]
struct Callback(SystemId);
#[derive(Component)]
struct Triggered;
fn setup(world: &mut World) {
let button_pressed_id = world.register_system(button_pressed);
world.spawn((Callback(button_pressed_id), Triggered));
// This entity does not have a Triggered component, so its callback won't run.
let slider_toggled_id = world.register_system(slider_toggled);
world.spawn(Callback(slider_toggled_id));
world.run_system_once(count_entities);
}
fn button_pressed() {
println!("A button was pressed!");
}
fn slider_toggled() {
println!("A slider was toggled!");
}
/// Runs the systems associated with each `Callback` component if the entity also has a Triggered component.
///
/// This could be done in an exclusive system rather than using `Commands` if preferred.
fn evaluate_callbacks(query: Query<&Callback, With<Triggered>>, mut commands: Commands) {
for callback in query.iter() {
commands.run_system(callback.0);
}
}