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>>;