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 .run();
11}
12
13fn setup(mut commands: Commands) {
14 let agent = commands.spawn(SequentialActions).id();
15 commands.actions(agent).add(ActionSequence::new(actions![
16 PrintAction("see"),
17 PrintAction("you"),
18 PrintAction("in"),
19 PrintAction("space"),
20 PrintAction("cowboy"),
21 |_agent, world: &mut World| -> bool {
22 world.send_event(AppExit::Success);
23 true
24 }
25 ]));
26}
27
28struct ActionSequence<const N: usize> {
29 actions: [BoxedAction; N],
30 index: usize,
31 canceled: bool,
32}
33
34impl<const N: usize> ActionSequence<N> {
35 fn new(actions: [BoxedAction; N]) -> Self {
36 Self {
37 actions,
38 index: 0,
39 canceled: false,
40 }
41 }
42}
43
44impl<const N: usize> Action for ActionSequence<N> {
45 fn is_finished(&self, agent: Entity, world: &World) -> bool {
46 self.actions[self.index].is_finished(agent, world)
47 }
48
49 fn on_add(&mut self, agent: Entity, world: &mut World) {
50 self.actions
51 .iter_mut()
52 .for_each(|action| action.on_add(agent, world));
53 }
54
55 fn on_start(&mut self, agent: Entity, world: &mut World) -> bool {
56 self.actions[self.index].on_start(agent, world)
57 }
58
59 fn on_stop(&mut self, agent: Option<Entity>, world: &mut World, reason: StopReason) {
60 self.actions[self.index].on_stop(agent, world, reason);
61 self.canceled = reason == StopReason::Canceled;
62 }
63
64 fn on_remove(&mut self, agent: Option<Entity>, world: &mut World) {
65 self.actions[self.index].on_remove(agent, world);
66 }
67
68 fn on_drop(mut self: Box<Self>, agent: Option<Entity>, world: &mut World, reason: DropReason) {
69 self.index += 1;
70
71 if self.index >= N {
72 return;
73 }
74
75 if self.canceled || reason != DropReason::Done {
76 for i in self.index..N {
77 self.actions[i].on_remove(agent, world);
78 }
79 return;
80 }
81
82 let Some(agent) = agent else { return };
83
84 world
85 .actions(agent)
86 .start(false)
87 .order(AddOrder::Front)
88 .add(self as BoxedAction);
89 }
90}
91
92struct PrintAction(&'static str);
93
94impl Action for PrintAction {
95 fn is_finished(&self, _agent: Entity, _world: &World) -> bool {
96 true
97 }
98
99 fn on_start(&mut self, _agent: Entity, _world: &mut World) -> bool {
100 println!("{}", self.0);
101 false
102 }
103
104 fn on_stop(&mut self, _agent: Option<Entity>, _world: &mut World, _reason: StopReason) {}
105}