moonshine_behavior/
events.rs

1//! Each [`Behavior`] [`Transition`](crate::transition::Transition) triggers an [`Event`].
2//!
3//! You may use these events to react to transitions and define the behavior logic.
4//!
5//! ## Behavior Indices
6//!
7//! Most events contain a [`BehaviorIndex`] which may be used to identify the exact state associated with the event.
8//! You may use [`Index`](std::ops::Index) operator to access the associated state.
9//!
10//! ## Initialization
11//!
12//! On spawn, several [`Behavior`] states may be activated at the same time. This can happen if the entity is reloaded from
13//! disk or synchronized from the network, for example.
14//!
15//! For technical reasons, you may need to perform different logic in such cases.
16//!
17//! For example, considering the following scenario:
18//! Let's imagine we're trying to model a car. When the car starts, we want to play an engine start audio clip.
19//! However, if the car has been turned on, and is now being loaded from disk, we should skip the engine start audio clip.
20//! You may use the `.initial` flag on the behavior events to branch your logic.
21//!
22//! # Example
23//! ```rust
24//! use bevy::prelude::*;
25//! use moonshine_behavior::prelude::*;
26//!
27//! #[derive(Component, Debug, Reflect)]
28//! #[reflect(Component)]
29//! struct B;
30//!
31//! impl Behavior for B {}
32//!
33//! fn on_start(event: OnStart<B>, query: Query<BehaviorRef<B>>) {
34//!     let behavior = query.get(*event.instance).unwrap();
35//!     let state = &behavior[event.index];
36//!
37//!     if event.initial {
38//!         /* Custom initialization logic */
39//!     }
40//!
41//!     /* ... */
42//! }
43//!
44//! fn on_pause(event: OnPause<B>, query: Query<BehaviorRef<B>>) {
45//!     let behavior = query.get(*event.instance).unwrap();
46//!     let state = &behavior[event.index];
47//!     /* ... */
48//! }
49//!
50//! fn on_resume(event: OnResume<B>, query: Query<BehaviorRef<B>>) {
51//!     let behavior = query.get(*event.instance).unwrap();
52//!     let state = &behavior[event.index];
53//!     /* ... */
54//! }
55//!
56//! fn on_activate(event: OnActivate<B>, query: Query<BehaviorRef<B>>) {
57//!     let behavior = query.get(*event.instance).unwrap();
58//!     let state = &behavior[event.index];
59//!     /* ... */
60//! }
61//!
62//! fn on_stop(event: OnStop<B>) {
63//!     let state = &event.behavior;
64//!     /* ... */
65//! }
66//! ```
67//!
68//! ##
69
70use bevy_ecs::event::EntityTrigger;
71use bevy_ecs::prelude::*;
72use moonshine_kind::{impl_entity_event_from_instance, prelude::*};
73
74use crate::transition::TransitionError;
75use crate::{Behavior, BehaviorIndex};
76
77/// An event which is triggered when a [`Behavior`] starts.
78///
79/// See [`OnStart`] for a more ergonomic type alias for use in systems.
80#[derive(Event)]
81#[event(trigger = EntityTrigger)]
82pub struct Start<T: Behavior> {
83    /// Target of this [`EntityEvent`].
84    pub instance: Instance<T>,
85    /// The index of the behavior that was started.
86    pub index: BehaviorIndex,
87    /// If true, it implies the behavior is initializing. See [module documention](self) for details.
88    pub initial: bool,
89}
90
91impl_entity_event_from_instance!(Start<T> where T: Behavior);
92
93/// An event which is triggered when a [`Behavior`] is paused.
94///
95/// See [`OnPause`] for a more ergonomic type alias for use in systems.
96#[derive(Event)]
97#[event(trigger = EntityTrigger)]
98pub struct Pause<T: Behavior> {
99    /// Target of this [`EntityEvent`].
100    pub instance: Instance<T>,
101    /// The index of the behavior that was paused.
102    pub index: BehaviorIndex,
103}
104
105impl_entity_event_from_instance!(Pause<T> where T: Behavior);
106
107/// An event which is triggered when a [`Behavior`] is resumed.
108///
109/// See [`OnResume`] for a more ergonomic type alias for use in systems.
110#[derive(Event)]
111#[event(trigger = EntityTrigger)]
112pub struct Resume<T: Behavior> {
113    /// Target of this [`EntityEvent`].
114    pub instance: Instance<T>,
115    /// The index of the behavior that was resumed.
116    pub index: BehaviorIndex,
117}
118
119impl_entity_event_from_instance!(Resume<T> where T: Behavior);
120
121/// An event which is triggered when a [`Behavior`] is started OR resumed.
122///
123/// See [`OnActivate`] for a more ergonomic type alias for use in systems.
124#[derive(Event)]
125#[event(trigger = EntityTrigger)]
126pub struct Activate<T: Behavior> {
127    /// Target of this [`EntityEvent`].
128    pub instance: Instance<T>,
129    /// The index of the behavior that was activated.
130    pub index: BehaviorIndex,
131    /// Whether the behavior was resumed or started.
132    pub resume: bool,
133    /// If true, it implies the behavior is initializing. See [module documention](self) for details.
134    pub initial: bool,
135}
136
137impl_entity_event_from_instance!(Activate<T> where T: Behavior);
138
139// TODO: OnSuspend, This gets tricky because the behavior state is already gone in `OnStop` ...
140
141/// An event which is triggered when a [`Behavior`] is stopped.
142///
143/// Unlike other events, this one does not provide a behavior index.
144///
145/// See [`OnStop`] for a more ergonomic type alias for use in systems.
146#[derive(Event)]
147#[event(trigger = EntityTrigger)]
148pub struct Stop<T: Behavior> {
149    /// Target of this [`EntityEvent`].
150    pub instance: Instance<T>,
151    /// The index of the behavior that was stopped.
152    pub index: BehaviorIndex,
153    /// The behavior that was stopped.
154    pub behavior: T,
155    /// If true, it indicates the behavior was stopped because it was interrupted.
156    pub interrupt: bool,
157}
158
159impl_entity_event_from_instance!(Stop<T> where T: Behavior);
160
161/// An event which is triggered when a [`TransitionError`] occurs.
162///
163/// See [`OnError`] for a more ergonomic type alias for use in systems.
164#[derive(Event)]
165#[event(trigger = EntityTrigger)]
166pub struct Error<T: Behavior> {
167    /// Target of this [`EntityEvent`].
168    pub instance: Instance<T>,
169    /// The associated [`TransitionError`].
170    pub error: TransitionError<T>,
171}
172
173impl_entity_event_from_instance!(Error<T> where T: Behavior);
174
175/// Alias for [`On<Start<T>>`](`Start`)
176pub type OnStart<'w, 't, T> = On<'w, 't, Start<T>>;
177
178/// Alias for [`On<Pause<T>>`](`Pause`)
179pub type OnPause<'w, 't, T> = On<'w, 't, Pause<T>>;
180
181/// Alias for [`On<Resume<T>>`](`Resume`)
182pub type OnResume<'w, 't, T> = On<'w, 't, Resume<T>>;
183
184/// Alias for [`On<Activate<T>>`](`Activate`)
185pub type OnActivate<'w, 't, T> = On<'w, 't, Activate<T>>;
186
187/// Alias for [`On<Stop<T>>`](`Stop`)
188pub type OnStop<'w, 't, T> = On<'w, 't, Stop<T>>;
189
190/// Alias for [`On<Error<T>>`](`Error`)
191pub type OnError<'w, 't, T> = On<'w, 't, Error<T>>;