parallel/
parallel.rs

1use bevy_app::{prelude::*, AppExit, ScheduleRunnerPlugin};
2use bevy_ecs::prelude::*;
3
4use bevy_sequential_actions::*;
5
6fn main() {
7    App::new()
8        .add_plugins((ScheduleRunnerPlugin::default(), SequentialActionsPlugin))
9        .add_systems(Startup, setup)
10        .add_systems(Update, countdown)
11        .run();
12}
13
14fn setup(mut commands: Commands) {
15    let agent = commands.spawn(SequentialActions).id();
16    commands.actions(agent).add((
17        ParallelActions::new(actions![
18            PrintAction("hello"),
19            CountdownAction::new(2),
20            PrintAction("world"),
21            CountdownAction::new(4),
22        ]),
23        |_agent, world: &mut World| {
24            world.send_event(AppExit::Success);
25            false
26        },
27    ));
28}
29
30struct ParallelActions<const N: usize> {
31    actions: [BoxedAction; N],
32}
33
34impl<const N: usize> ParallelActions<N> {
35    const fn new(actions: [BoxedAction; N]) -> Self {
36        Self { actions }
37    }
38}
39
40impl<const N: usize> Action for ParallelActions<N> {
41    fn is_finished(&self, agent: Entity, world: &World) -> bool {
42        self.actions
43            .iter()
44            .all(|action| action.is_finished(agent, world))
45    }
46
47    fn on_add(&mut self, agent: Entity, world: &mut World) {
48        self.actions
49            .iter_mut()
50            .for_each(|action| action.on_add(agent, world));
51    }
52
53    fn on_start(&mut self, agent: Entity, world: &mut World) -> bool {
54        std::array::from_fn::<bool, N, _>(|i| self.actions[i].on_start(agent, world))
55            .into_iter()
56            .all(|b| b)
57    }
58
59    fn on_stop(&mut self, agent: Option<Entity>, world: &mut World, reason: StopReason) {
60        self.actions
61            .iter_mut()
62            .for_each(|action| action.on_stop(agent, world, reason));
63    }
64
65    fn on_remove(&mut self, agent: Option<Entity>, world: &mut World) {
66        self.actions
67            .iter_mut()
68            .for_each(|action| action.on_remove(agent, world));
69    }
70}
71
72struct PrintAction(&'static str);
73
74impl Action for PrintAction {
75    fn is_finished(&self, _agent: Entity, _world: &World) -> bool {
76        true
77    }
78
79    fn on_start(&mut self, _agent: Entity, _world: &mut World) -> bool {
80        println!("{}", self.0);
81        true
82    }
83
84    fn on_stop(&mut self, _agent: Option<Entity>, _world: &mut World, _reason: StopReason) {}
85}
86
87struct CountdownAction {
88    count: u32,
89    entity: Entity,
90}
91
92impl CountdownAction {
93    const fn new(count: u32) -> Self {
94        Self {
95            count,
96            entity: Entity::PLACEHOLDER,
97        }
98    }
99}
100
101impl Action for CountdownAction {
102    fn is_finished(&self, _agent: Entity, world: &World) -> bool {
103        world.get::<Countdown>(self.entity).unwrap().0 == 0
104    }
105
106    fn on_add(&mut self, _agent: Entity, world: &mut World) {
107        self.entity = world.spawn_empty().id();
108    }
109
110    fn on_start(&mut self, agent: Entity, world: &mut World) -> bool {
111        let mut entity = world.entity_mut(self.entity);
112
113        if entity.contains::<Paused>() {
114            entity.remove::<Paused>();
115        } else {
116            entity.insert(Countdown(self.count));
117            println!("Countdown({}): {}", self.entity, self.count);
118        }
119
120        self.is_finished(agent, world)
121    }
122
123    fn on_stop(&mut self, _agent: Option<Entity>, world: &mut World, reason: StopReason) {
124        if reason == StopReason::Paused {
125            world.entity_mut(self.entity).insert(Paused);
126        }
127    }
128
129    fn on_remove(&mut self, _agent: Option<Entity>, world: &mut World) {
130        world.despawn(self.entity);
131    }
132}
133
134#[derive(Component)]
135struct Countdown(u32);
136
137#[derive(Component)]
138struct Paused;
139
140fn countdown(mut countdown_q: Query<(Entity, &mut Countdown), Without<Paused>>) {
141    for (entity, mut countdown) in &mut countdown_q {
142        countdown.0 = countdown.0.saturating_sub(1);
143        println!("Countdown({}): {}", entity, countdown.0);
144    }
145}