moonshine_behavior/
transition.rs1use std::collections::VecDeque;
6use std::fmt::Debug;
7
8use bevy_ecs::component::Components;
9use bevy_ecs::prelude::*;
10use bevy_log::prelude::*;
11use bevy_reflect::prelude::*;
12use moonshine_kind::prelude::*;
13
14use crate::events::{OnActivate, OnStart};
15use crate::{Behavior, BehaviorHooks, BehaviorIndex, BehaviorMut, BehaviorMutItem, Memory};
16
17pub use self::Transition::{Interrupt, Next, Previous};
18
19#[derive(Component, Clone, Debug, Reflect)]
24#[require(Memory<T>)]
25#[reflect(Component)]
26pub enum Transition<T: Behavior> {
27 #[doc(hidden)]
28 None,
29 Next(T),
31 Interrupt(Interruption<T>),
33 Previous,
35}
36
37impl<T: Behavior> Transition<T> {
38 pub fn is_none(&self) -> bool {
40 matches!(self, Self::None)
41 }
42
43 fn take(&mut self) -> Self {
44 std::mem::replace(self, Transition::None)
45 }
46}
47
48impl<T: Behavior> Default for Transition<T> {
49 fn default() -> Self {
50 Self::None
51 }
52}
53
54pub fn transition<T: Behavior>(
56 components: &Components,
57 mut query: Query<
58 (
59 Instance<T>,
60 BehaviorMut<T>,
61 Option<&mut TransitionSequence<T>>,
62 ),
63 Or<(Changed<Transition<T>>, With<TransitionSequence<T>>)>,
64 >,
65 mut commands: Commands,
66) {
67 for (instance, mut behavior, sequence_opt) in &mut query {
68 if behavior.current.is_added() {
69 debug_assert!(behavior.memory.is_empty());
71
72 behavior.invoke_start(None, commands.instance(instance));
74 let id = components.valid_component_id::<T>().unwrap();
75 commands.trigger_targets(
76 OnStart {
77 index: BehaviorIndex::initial(),
78 },
79 (*instance, id),
80 );
81 commands.trigger_targets(
82 OnActivate {
83 index: BehaviorIndex::initial(),
84 resume: false,
85 },
86 (*instance, id),
87 );
88 }
89
90 let mut stop_index = None;
92
93 let mut interrupt_sequence = false;
94
95 match behavior.transition.take() {
96 Next(next) => {
97 interrupt_sequence = !behavior.push(instance, next, components, &mut commands);
98 }
99 Previous => {
100 stop_index = Some(behavior.index());
101 interrupt_sequence = !behavior.pop(instance, components, &mut commands);
102 }
103 Interrupt(Interruption::Start(next)) => {
104 behavior.interrupt(instance, next, components, &mut commands);
105 interrupt_sequence = true;
106 }
107 Interrupt(Interruption::Resume(index)) => {
108 behavior.clear(instance, index, components, &mut commands);
109 interrupt_sequence = true;
110 }
111 _ => {}
112 }
113
114 let Some(sequence) = sequence_opt else {
115 continue;
116 };
117
118 if interrupt_sequence {
119 debug!("{instance:?}: sequence interrupted");
120 commands.entity(*instance).remove::<TransitionSequence<T>>();
121 } else if sequence.is_empty() {
122 debug!("{instance:?}: sequence finished");
123 commands.entity(*instance).remove::<TransitionSequence<T>>();
124 } else {
125 TransitionSequence::update(sequence, instance, behavior, stop_index);
126 }
127 }
128}
129
130#[derive(Debug, Clone, Reflect)]
132pub enum Interruption<T: Behavior> {
133 Start(T),
136 Resume(BehaviorIndex),
138}
139
140#[doc(hidden)]
141#[deprecated(since = "0.2.1", note = "use `Changed<Transition<T>>` instead")]
142pub type TransitionChanged<T> = Or<(Changed<Transition<T>>, With<TransitionSequence<T>>)>;
143
144#[derive(Debug, PartialEq, Reflect)]
146pub enum TransitionError<T: Behavior> {
147 RejectedNext(T),
149 NoPrevious,
151}
152
153#[derive(Component, Reflect)]
155#[reflect(Component)]
156pub struct TransitionSequence<T: Behavior> {
157 queue: VecDeque<TransitionSequenceElement<T>>,
158 wait_index: Option<BehaviorIndex>,
159}
160
161impl<T: Behavior> TransitionSequence<T> {
162 pub fn new(items: impl IntoIterator<Item = T>) -> Self {
164 Self {
165 queue: VecDeque::from_iter(items.into_iter().map(TransitionSequenceElement::Start)),
166 wait_index: None,
167 }
168 }
169
170 pub fn empty() -> Self {
172 Self {
173 queue: VecDeque::new(),
174 wait_index: None,
175 }
176 }
177
178 pub fn start(next: T) -> Self {
180 let mut sequence = Self::empty();
181 sequence.push(TransitionSequenceElement::Start(next));
182 sequence
183 }
184
185 pub fn wait_for(next: T) -> Self {
187 Self::empty().then_wait_for(next)
188 }
189
190 pub fn is_empty(&self) -> bool {
192 self.queue.is_empty()
193 }
194
195 pub fn len(&self) -> usize {
197 self.queue.len()
198 }
199
200 pub fn then(mut self, next: T) -> Self {
202 self.push(TransitionSequenceElement::Start(next));
203 self
204 }
205
206 pub fn then_wait_for(mut self, next: T) -> Self {
208 self.push(TransitionSequenceElement::StartWait(next));
209 self
210 }
211
212 pub fn then_stop(mut self) -> Self {
214 self.push(TransitionSequenceElement::Stop);
215 self
216 }
217
218 fn push(&mut self, next: TransitionSequenceElement<T>) {
219 self.queue.push_back(next);
220 }
221}
222
223impl<T: Behavior> TransitionSequence<T> {
224 pub(crate) fn update(
225 mut this: Mut<Self>,
226 instance: Instance<T>,
227 mut behavior: BehaviorMutItem<T>,
228 stop_index: Option<BehaviorIndex>,
229 ) {
230 debug_assert!(!this.queue.is_empty());
231
232 if let Some(wait_index) = this.wait_index {
233 if let Some(stop_index) = stop_index {
234 if wait_index != stop_index {
235 return;
236 }
237 } else {
238 return;
239 }
240 }
241
242 debug!("{instance:?}: sequence steps = {:?}", this.queue.len());
243
244 if let Some(element) = this.queue.pop_front() {
245 use TransitionSequenceElement::*;
246 match element {
247 Start(next) => {
248 this.wait_index = None;
249 behavior.start(next);
250 }
251 StartWait(next) => {
252 this.wait_index = Some(behavior.index().next());
253 behavior.start(next);
254 }
255 Stop => {
256 this.wait_index = None;
257 behavior.stop();
258 }
259 }
260 }
261 }
262}
263
264#[derive(Debug, Reflect)]
265enum TransitionSequenceElement<T: Behavior> {
266 Start(T),
267 StartWait(T),
268 Stop,
269}