moonshine_behavior/
transition.rs

1//! A [`Behavior`] is controlled using [`Transition`].
2//!
3//! Transitions are processed by the [`transition`] system.
4
5use std::collections::VecDeque;
6use std::fmt::Debug;
7
8use bevy_ecs::event::EntityTrigger;
9use bevy_ecs::prelude::*;
10use bevy_log::prelude::*;
11use bevy_reflect::prelude::*;
12use moonshine_kind::prelude::*;
13use moonshine_util::prelude::*;
14
15use crate::events::Start;
16use crate::{
17    Behavior, BehaviorHooks, BehaviorIndex, BehaviorItem, BehaviorMut, BehaviorMutItem, Memory,
18};
19
20pub use self::Transition::{Interrupt, Next, Previous};
21
22/// A [`Component`] which controls transitions between [`Behavior`] states.
23///
24/// This component is automatically registered as a required component for all types
25/// which implement the [`Behavior`] trait and and have their [`BehaviorPlugin`](crate::plugin::BehaviorPlugin) added.
26#[derive(Component, Default, Clone, Debug, Reflect)]
27#[require(Expect<T>, Memory<T>)]
28#[reflect(Component)]
29pub enum Transition<T: Behavior> {
30    #[doc(hidden)]
31    #[default]
32    None,
33    /// Starts the next behavior.
34    Next(T),
35    /// Starts an [`Interruption`].
36    Interrupt(Interruption<T>),
37    /// Stops the current behavior and resumes the previous one.
38    Previous,
39}
40
41impl<T: Behavior> Transition<T> {
42    /// Returns `true` if there are no pending transitions.
43    pub fn is_none(&self) -> bool {
44        matches!(self, Self::None)
45    }
46
47    fn take(&mut self) -> Self {
48        std::mem::replace(self, Transition::None)
49    }
50}
51
52/// A system which processes [`Behavior`] [`Transitions`](Transition).
53#[allow(clippy::type_complexity)]
54pub fn transition<T: Behavior>(
55    mut query: Query<
56        (Instance<T>, BehaviorMut<T>, Option<&mut TransitionQueue<T>>),
57        Or<(Changed<Transition<T>>, With<TransitionQueue<T>>)>,
58    >,
59    mut commands: Commands,
60) {
61    for (instance, mut behavior, queue_opt) in &mut query {
62        let entity = instance.entity();
63
64        if behavior.is_added() {
65            let mut stack: VecDeque<T> = behavior
66                .memory
67                .bypass_change_detection()
68                .drain(..)
69                .collect();
70
71            if !stack.is_empty() {
72                let mut initial = stack.pop_front().unwrap();
73                let current = {
74                    std::mem::swap(behavior.current.as_mut(), &mut initial);
75                    initial
76                };
77
78                stack.push_back(current);
79            }
80
81            behavior.invoke_start(None, commands.instance(instance));
82            commands.queue(move |world: &mut World| {
83                world.trigger_with(
84                    Start {
85                        instance,
86                        index: BehaviorIndex::initial(),
87                        initial: true,
88                    },
89                    EntityTrigger,
90                );
91            });
92
93            for state in stack {
94                let _ = behavior.push(instance, state, true, &mut commands);
95            }
96        }
97
98        // Index of the stopped behavior, if applicable.
99        let mut stop_index = None;
100
101        let mut interrupt_queue = false;
102
103        match behavior.transition.take() {
104            Next(next) => {
105                interrupt_queue = !behavior.push(instance, next, false, &mut commands);
106            }
107            Previous => {
108                stop_index = Some(behavior.current_index());
109                interrupt_queue = !behavior.pop(instance, &mut commands);
110            }
111            Interrupt(Interruption::Start(next)) => {
112                behavior.interrupt(instance, next, &mut commands);
113                interrupt_queue = true;
114            }
115            Interrupt(Interruption::Resume(index)) => {
116                behavior.clear(instance, index, &mut commands);
117                interrupt_queue = true;
118            }
119            _ => {}
120        }
121
122        let Some(queue) = queue_opt else {
123            continue;
124        };
125
126        if interrupt_queue {
127            debug!("{instance:?}: queue interrupted");
128            commands.entity(entity).remove::<TransitionQueue<T>>();
129        } else if queue.is_empty() {
130            debug!("{instance:?}: queue finished");
131            commands.entity(entity).remove::<TransitionQueue<T>>();
132        } else {
133            TransitionQueue::update(queue, instance, behavior, stop_index);
134        }
135    }
136}
137
138/// A specific kind of [`Transition`] which may stop active behaviors before activating a new one.
139#[derive(Debug, Clone, Reflect)]
140pub enum Interruption<T: Behavior> {
141    /// An interruption which stops any behavior which [yields](Behavior::filter_yield)
142    /// to the given behavior, and then starts it.
143    Start(T),
144    /// An interruption which resumes a behavior at the given index by stopping all other behaviors above it in the stack.
145    Resume(BehaviorIndex),
146}
147
148#[doc(hidden)]
149#[deprecated(since = "0.2.1", note = "use `Changed<Transition<T>>` instead")]
150pub type TransitionChanged<T> = Or<(Changed<Transition<T>>, With<TransitionQueue<T>>)>;
151
152/// Represents an error during [`transition`].
153#[derive(Debug, PartialEq, Reflect)]
154pub enum TransitionError<T: Behavior> {
155    /// The given behavior was rejected by [`filter_next`](Behavior::filter_next).
156    RejectedNext(T),
157    /// Initial behavior may not be stopped.
158    NoPrevious,
159}
160
161#[doc(hidden)]
162#[deprecated(since = "0.3.1", note = "use `TransitionQueue` instead")]
163pub type TransitionSequence<T> = TransitionQueue<T>;
164
165/// A queue of transitions to be invoked automatically.
166#[derive(Component, Reflect)]
167#[reflect(Component)]
168#[require(Expect<Transition<T>>)]
169pub struct TransitionQueue<T: Behavior> {
170    queue: VecDeque<TransitionQueueItem<T>>,
171    wait_for: Option<BehaviorIndex>,
172}
173
174impl<T: Behavior> TransitionQueue<T> {
175    /// Creates a new [`TransitionQueue`] which starts each given behavior in order.
176    ///
177    /// Unlike [`TransitionQueue::sequence`], a chain does not wait for the behaviors to stop
178    /// and starts the behaviors on top of each other. This is useful when you wish to load a set of
179    /// states onto the behavior stack (i.e. "Bird must Fly *and* Chirp").
180    ///
181    /// You must ensure that each transition in the chain is allowed (see [`Behavior::filter_next`]).
182    /// The sequence will stop if any transition fails.
183    pub fn chain(items: impl IntoIterator<Item = T>) -> Self {
184        Self {
185            queue: VecDeque::from_iter(items.into_iter().map(TransitionQueueItem::Start)),
186            wait_for: None,
187        }
188    }
189
190    /// Creates a new [`TransitionQueue`] which starts each given behavior in order,
191    /// waiting for each one to stop before starting the next.
192    ///
193    /// Unlike [`TransitionQueue::chain`], a sequence waits for each behavior to stop before starting the next.
194    /// This is useful when you want to queue some actions after each other (e.g. "Bird must Chirp, *then* Fly").
195    ///
196    /// You must ensure each transition from the current behavior to all elements in
197    /// the sequence is allowed (see [`Behavior::filter_next`]).
198    /// The sequence will stop if any transition fails.
199    pub fn sequence(items: impl IntoIterator<Item = T>) -> Self {
200        Self {
201            queue: VecDeque::from_iter(items.into_iter().map(TransitionQueueItem::StartWait)),
202            wait_for: None,
203        }
204    }
205
206    /// Creates an empty [`TransitionQueue`].
207    pub fn empty() -> Self {
208        Self {
209            queue: VecDeque::new(),
210            wait_for: None,
211        }
212    }
213
214    /// Creates a new [`TransitionQueue`] which starts with the given [`Behavior`].
215    pub fn start(next: T) -> Self {
216        let mut sequence = Self::empty();
217        sequence.push(TransitionQueueItem::Start(next));
218        sequence
219    }
220
221    /// Creates a new [`TransitionQueue`] which starts by stopping the current [`Behavior`].
222    pub fn stop() -> Self {
223        let mut sequence = Self::empty();
224        sequence.push(TransitionQueueItem::Stop);
225        sequence
226    }
227
228    /// Creates a new [`TransitionQueue`] which starts with the given [`Behavior`] and waits for it to stop.
229    pub fn wait_for(next: T) -> Self {
230        Self::empty().then_wait_for(next)
231    }
232
233    /// Returns `true` if the [`TransitionQueue`] is empty.
234    pub fn is_empty(&self) -> bool {
235        self.queue.is_empty()
236    }
237
238    /// Returns the number of transitions in the [`TransitionQueue`].
239    pub fn len(&self) -> usize {
240        self.queue.len()
241    }
242
243    /// Extends the [`TransitionQueue`] by starting the next [`Behavior`].
244    pub fn then(mut self, next: T) -> Self {
245        self.push(TransitionQueueItem::Start(next));
246        self
247    }
248
249    /// Extends the [`TransitionQueue`] by starting the next [`Behavior`] if and only if `condition` is true.
250    ///
251    /// This is just a convenient shortcut useful when creating complex queues, for example:
252    /// ```
253    /// use bevy::prelude::*;
254    /// use moonshine_behavior::prelude::*;
255    ///
256    /// #[derive(Component, Debug)]
257    /// pub enum Foo {
258    ///     Bar,
259    ///     Baz,
260    /// }
261    ///
262    /// impl Behavior for Foo {}
263    ///
264    /// fn make_queue(baz: bool) -> TransitionQueue<Foo> {
265    ///     TransitionQueue::start(Foo::Bar).then_if(baz, Foo::Baz)
266    /// }
267    /// ```
268    pub fn then_if(self, condition: bool, next: T) -> Self {
269        if condition {
270            return self.then(next);
271        }
272        self
273    }
274
275    /// Extends the [`TransitionQueue`] by starting the next [`Behavior`] and waiting for it to stop.
276    pub fn then_wait_for(mut self, next: T) -> Self {
277        self.push(TransitionQueueItem::StartWait(next));
278        self
279    }
280
281    /// Extends the [`TransitionQueue`] by stopping the current [`Behavior`].
282    pub fn then_stop(mut self) -> Self {
283        self.push(TransitionQueueItem::Stop);
284        self
285    }
286
287    fn push(&mut self, next: TransitionQueueItem<T>) {
288        self.queue.push_back(next);
289    }
290}
291
292impl<T: Behavior> TransitionQueue<T> {
293    pub(crate) fn update(
294        mut this: Mut<Self>,
295        instance: Instance<T>,
296        mut behavior: BehaviorMutItem<T>,
297        stop_index: Option<BehaviorIndex>,
298    ) {
299        debug_assert!(!this.is_empty());
300
301        if let Some(wait_index) = this.wait_for {
302            if let Some(stop_index) = stop_index {
303                if wait_index != stop_index {
304                    return;
305                }
306            } else {
307                return;
308            }
309        }
310
311        debug!("{instance:?}: queue length = {:?}", this.len());
312
313        if let Some(element) = this.queue.pop_front() {
314            use TransitionQueueItem::*;
315            match element {
316                Start(next) => {
317                    this.wait_for = None;
318                    behavior.start(next);
319                }
320                StartWait(next) => {
321                    this.wait_for = Some(behavior.current_index().next());
322                    behavior.start(next);
323                }
324                Stop => {
325                    this.wait_for = None;
326                    behavior.stop();
327                }
328            }
329        }
330    }
331}
332
333#[derive(Debug, Reflect)]
334enum TransitionQueueItem<T: Behavior> {
335    Start(T),
336    StartWait(T),
337    Stop,
338}