mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 22:50:19 +00:00
e4b368721d
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>
59 lines
1.8 KiB
Rust
59 lines
1.8 KiB
Rust
//! 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`](bevy::ecs::World::run_system) or
|
|
//! [`World::run_system_once`](bevy::ecs::World::run_system_once) docs for more
|
|
//! details.
|
|
|
|
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);
|
|
}
|
|
}
|