macroquad_ply/experimental/
state_machine.rs1use crate::experimental::coroutines::Coroutine;
2
3use crate::experimental::scene;
4
5type UpdateFn<T> = Box<dyn FnMut(&mut scene::RefMut<T>, f32)>;
6type CoroutineFn<T> = Box<dyn FnMut(&mut scene::RefMut<T>) -> Coroutine>;
7type OnEndFn<T> = Box<dyn FnMut(&mut scene::RefMut<T>)>;
8
9pub struct State<T: 'static> {
10 update: Option<UpdateFn<T>>,
11 coroutine: Option<CoroutineFn<T>>,
12 on_end: Option<OnEndFn<T>>,
13}
14
15impl<T> State<T> {
16 pub fn new() -> Self {
17 State {
18 update: None,
19 coroutine: None,
20 on_end: None,
21 }
22 }
23
24 pub fn update(self, update: impl FnMut(&mut scene::RefMut<T>, f32) + 'static) -> Self {
25 State {
26 update: Some(Box::new(update)),
27 ..self
28 }
29 }
30
31 pub fn coroutine(
32 self,
33 coroutine: impl FnMut(&mut scene::RefMut<T>) -> Coroutine + 'static,
34 ) -> Self {
35 State {
36 coroutine: Some(Box::new(coroutine)),
37 ..self
38 }
39 }
40
41 pub fn on_end(self, on_end: impl FnMut(&mut scene::RefMut<T>) + 'static) -> Self {
42 State {
43 on_end: Some(Box::new(on_end)),
44 ..self
45 }
46 }
47}
48
49pub enum StateMachine<T: 'static> {
50 Ready(StateMachineOwned<T>),
51 InUse {
52 next_state: Option<usize>,
53 current_state: usize,
54 },
55}
56
57impl<T: scene::Node + 'static> StateMachine<T> {
58 pub fn new() -> StateMachine<T> {
59 StateMachine::Ready(StateMachineOwned::new())
60 }
61
62 pub fn add_state(&mut self, id: usize, state: State<T>) {
63 match self {
64 StateMachine::Ready(state_machine) => state_machine.insert(id, state),
65 _ => panic!(),
66 }
67 }
68
69 pub fn take(&mut self) -> StateMachineOwned<T> {
70 let current_state = self.state();
71 match std::mem::replace(
72 self,
73 StateMachine::InUse {
74 next_state: None,
75 current_state,
76 },
77 ) {
78 StateMachine::InUse { .. } => panic!(),
79 StateMachine::Ready(state_machine) => state_machine,
80 }
81 }
82
83 fn put_back(&mut self, mut state_machine: StateMachineOwned<T>) {
84 match self {
85 StateMachine::Ready(_) => panic!(),
86 StateMachine::InUse { next_state, .. } => {
87 if let Some(next_state) = next_state {
88 state_machine.set_state(*next_state);
89 }
90 }
91 }
92 *self = StateMachine::Ready(state_machine);
93 }
94
95 pub fn set_state(&mut self, state: usize) {
96 match self {
97 StateMachine::Ready(state_machine) => {
98 state_machine.set_state(state);
99 }
100 StateMachine::InUse {
101 ref mut next_state, ..
102 } => {
103 *next_state = Some(state);
104 }
105 }
106 }
107
108 pub const fn state(&self) -> usize {
109 match self {
110 StateMachine::Ready(state_machine) => state_machine.state(),
111 StateMachine::InUse {
112 ref current_state, ..
113 } => *current_state,
114 }
115 }
116
117 pub fn update_detached<'a, F>(mut t: scene::RefMut<T>, mut f: F)
119 where
120 F: FnMut(&mut scene::RefMut<T>) -> &mut StateMachine<T>,
121 {
122 let mut state_machine = f(&mut t).take();
123 state_machine.update(&mut t, crate::time::get_frame_time());
124
125 let handle = t.handle();
129 drop(t);
130 if let Some(ref mut coroutine) = state_machine.active_coroutine {
131 coroutine.poll(crate::time::get_frame_time() as _);
132 }
133 let mut t = crate::experimental::scene::get_node(handle);
134
135 f(&mut t).put_back(state_machine);
136 }
137
138 pub fn update<'a>(&mut self, t: &'a mut scene::RefMut<T>) {
139 match self {
140 StateMachine::Ready(state_machine) => {
141 state_machine.update(t, crate::time::get_frame_time())
142 }
143 _ => panic!(),
144 }
145 }
146}
147
148pub struct StateMachineOwned<T: 'static> {
149 states: Vec<State<T>>,
150 active_coroutine: Option<Coroutine>,
151 next_state: Option<usize>,
152 current_state: usize,
153}
154
155impl<T: 'static> StateMachineOwned<T> {
156 const MAX_STATE: usize = 32;
157
158 pub fn new() -> Self {
159 let mut states = vec![];
160 for _ in 0..Self::MAX_STATE {
161 states.push(State::new());
162 }
163 StateMachineOwned {
164 states,
165 active_coroutine: None,
166 next_state: None,
167 current_state: 0,
168 }
169 }
170
171 pub fn insert(&mut self, id: usize, state: State<T>) {
172 assert!(id < Self::MAX_STATE);
173
174 self.states[id] = state;
175 }
176
177 pub fn set_state(&mut self, state: usize) {
178 self.next_state = Some(state);
179 }
180
181 pub const fn state(&self) -> usize {
182 self.current_state
183 }
184
185 fn update(&mut self, player: &mut scene::RefMut<T>, dt: f32) {
186 if let Some(next_state) = self.next_state {
187 if next_state != self.current_state {
188 if let Some(on_end) = &mut self.states[self.current_state].on_end {
189 on_end(player);
190 }
191 if let Some(coroutine) = &mut self.states[next_state].coroutine {
192 let mut coroutine = coroutine(player);
193 coroutine.set_manual_poll();
194 self.active_coroutine = Some(coroutine);
195 }
196 }
197 self.current_state = next_state;
198 self.next_state = None;
199 }
200
201 if let Some(update) = self.states[self.current_state].update.as_mut() {
202 (update)(player, dt);
203 }
204 }
205}