1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
//! A state-of-the-art [utility AI](https://en.wikipedia.org/wiki/Utility_system) library for [Bevy Engine](https://bevyengine.org/).
//!
//! # Design Goals
//!
//! In order of priority:
//!
//! - **Correctness**
//! - Scoring entity trees are scored in depth-first post-order traversal, ensuring that all children are scored before their parents.
//! - **Ergonomics**:
//! - Adding scoring, picking, and actions to entities should have little boilerplate.
//! - **Modularity**:
//! - Adding new kinds of scoring and picking should be easy.
//! - Adding different ways of handling actions should be easy.
//! - Both turn-based and real-time games should be supported.
//! - **Performance**:
//! - Pay only for what you use: Scoring and picking observers are only added if they are used.
//! - Scoring and picking should be reasonably fast. Action performance is up to the user.
//!
//! # Crate Layout
//!
//! Utility AI is typically implemented as a 3-part lifecycle, and this library follows that pattern:
//! - [**Scoring**](crate::scoring): Entities evaluate the world around them and assign scores to themselves based on that evaluation.
//! - [**Picking**](crate::acting): Entities choose actions based on their scores.
//! - [**Acting**](crate::acting): Entities perform actions based on their picks.
//!
//! ## Scoring
//!
//! In this crate, actor entities hold the view into the world,
//! and child [`Score`] entities hold and calculate the scores based on that view.
//! These children can be nested to any depth, giving you the flexibility to score entities however complex you want.
//!
//! # Full Walkthrough Example
//!
//! ```rust
//! use bevy::{prelude::*, ecs::component::ComponentId};
//! use bevy_observed_utility::prelude::*;
//!
//! // To start our game, we'll need to create a new App.
//! let mut app = App::new();
//! // We'll also need to add the ObservedUtilityPlugins group which handles the whole lifecycle for us,
//! // leaving us to handle the features.
//! app.add_plugins(ObservedUtilityPlugins::RealTime);
//!
//! /// Define a component which provides a view into the world.
//! /// Just a normal component for our actor's thirst.
//! #[derive(Component)]
//! struct Thirst {
//! /// Goes from 0 to 100.
//! value: f32,
//! /// How much thirst increases per second.
//! per_second: f32,
//! }
//!
//! /// This impl allows us to use the score_ancestor function to score thirst, later on.
//! impl From<&Thirst> for Score {
//! fn from(thirst: &Thirst) -> Self {
//! Score::new(thirst.value / 100.)
//! }
//! }
//!
//! /// Update the actor's view into the world however you like. In this case, it's just slowly increasing over time.
//! /// Still just a normal system that runs at a fixed rate.
//! fn get_thirsty_over_time(time: Res<Time<Fixed>>, mut actors: Query<&mut Thirst>) {
//! for mut thirst in actors.iter_mut() {
//! thirst.value = (thirst.value + thirst.per_second * time.delta_seconds()).min(100.);
//! }
//! }
//! app.add_systems(FixedUpdate, get_thirsty_over_time);
//!
//! /// Now lets define a component to mark the score entity as measuring thirst.
//! /// As opposed to Thirst, this one stores no data; it's just a marker.
//! #[derive(Component)]
//! pub struct Thirsty;
//!
//! // The first of a few library-provided functions to reduce boilerplate is score_ancestor.
//! // It listens for the OnScore event and scores the entity using two generic parameters:
//! // - #1: The component to read from the closest parent/ancestor entity.
//! // - #2: The score entity with this marker component.
//! app.observe(score_ancestor::<Thirst, Thirsty>);
//!
//! /// Next we need an action to perform when the thirst is high enough.
//! /// This one also belongs to the actor, and is just a normal component.
//! #[derive(Component)]
//! pub struct Drinking {
//! /// This one's also from 0 to 100.
//! pub until: f32,
//! /// How much thirst is quenched per second.
//! pub per_second: f32,
//! }
//!
//! /// This impl is used when inserting the component onto the actor.
//! /// (its required for the on_action_initiated_insert_default observer later on)
//! impl Default for Drinking {
//! fn default() -> Self {
//! Self {
//! until: 10.,
//! per_second: 2.,
//! }
//! }
//! }
//!
//! /// We'll also need a default action for the actor to perform when it's not doing anything else.
//! #[derive(Component)]
//! pub struct Idle;
//!
//! /// We'll also need ComponentIds for these actions to later identify and perform lifecycle events on them.
//! #[derive(Resource)]
//! pub struct ActionIds {
//! pub idle: ComponentId,
//! pub drinking: ComponentId,
//! }
//!
//! /// We'll need to initialize the action ids somewhere later on.
//! /// Unfortunately initializing ComponentIds requires mutable access to the world, so we'll use FromWorld.
//! impl FromWorld for ActionIds {
//! fn from_world(world: &mut World) -> Self {
//! Self {
//! idle: world.init_component::<Idle>(),
//! drinking: world.init_component::<Drinking>(),
//! }
//! }
//! }
//!
//! // Go ahead and initialize it on the App:
//! app.init_resource::<ActionIds>();
//!
//! // The library provides a builtin function to handle the common case where
//! // an action is initiated and its component should be inserted onto the actor.
//! // Inserting this component will allow the actor to be targeted in the following system.
//! app.observe(on_action_initiated_insert_default::<Drinking>);
//!
//! /// Now we'll update all actors that are drinking.
//! /// This is a normal system that runs at a fixed rate.
//! fn drink(
//! mut commands: Commands,
//! time: Res<Time<Fixed>>,
//! mut actors: Query<(Entity, &mut Thirst, &Drinking)>,
//! actions: Res<ActionIds>
//! ) {
//! for (actor, mut thirst, drinking) in actors.iter_mut() {
//! // Quench the thirst a bit.
//! thirst.value = (thirst.value - drinking.per_second * time.delta_seconds()).max(0.);
//! // If the thirst is low enough, finish drinking.
//! if thirst.value <= drinking.until {
//! /// We'll need that ActionIds resource we created earlier to identify the action.
//! commands.trigger_targets(
//! OnActionEnded::completed(actions.drinking),
//! TargetedAction(actor, actions.drinking),
//! );
//! }
//! }
//! }
//! // Lets add the system to the app, and order it after the get_thirsty_over_time system.
//! app.add_systems(FixedUpdate, drink.after(get_thirsty_over_time));
//!
//! // Similar to on_action_initiated_insert_default, the library also provides a function
//! // to automatically remove the action's component from the actor when it ends.
//! app.observe(on_action_ended_remove::<Drinking>);
//!
//! // Now onto the real magic: spawning our entities!
//!
//! // We'll need a system that's executed on startup to spawn our actor entity and child score entity.
//! fn spawn_entities(mut commands: Commands, actions: Res<ActionIds>) {
//! // Let's build the tree from the bottom up, since it'll be easier to insert the Picker on the actor last.
//! // First, the entity that scores thirst.
//! let thirst = commands.spawn((Thirsty, Score::default())).id();
//!
//! // Spawn the actor entity
//! commands
//! .spawn((
//! // Remember the first component we defined? Put it on the actor.
//! Thirst {
//! value: 0.,
//! per_second: 1.,
//! },
//! // We actually have one more concept to introduce: the Picker.
//! // The Picker is a component that tells the system which action to perform based on the scores.
//! // All pickers need a default action to perform when they're not doing anything else.
//! Picker::new(actions.idle)
//! // When the actor gets thirsty enough, they'll drink.
//! .with(thirst, actions.drinking),
//! // To configure the picker's selection behavior, we insert a component that handles that.
//! // In this case, we'll insert the FirstToScore component,
//! // which picks the first action that scores above a certain threshold.
//! // There's other picker variants too, like Random and Highest.
//! FirstToScore::new(0.5),
//! // For action handling we'll need one final component: CurrentAction.
//! // This component holds the ComponentId of the action the actor is currently performing.
//! // Which makes it easy to check what the actor is doing.
//! // We'll spawn the actor idling.
//! CurrentAction(actions.idle),
//! ))
//! .add_child(thirst);
//! }
//!
//! // Register the system and run the app!
//! app.add_systems(Startup, spawn_entities);
//! app.run();
//! // Done!
//! ```
//!
//! # Optimizing for Performance
//!
//! While this library does its best to be performant, there are a few ways to improve performance in your game:
//! - Run scoring and picking systems at a slower fixed rate than default.
//! - This will induce latency in the AI, but will reduce overall frame time.
//! - Replace deeply nested scoring hierarchies with shallow hand-written scoring observers.
//!
//! [`Score`]: crate::scoring::Score
use ;
use crate::;
/// [`PluginGroup`] for all standard plugins in `bevy_observed_utility`.
/// [`Plugin`] which automatically runs scoring, picking, and perf systems in the configured [`Schedule`].
/// This plugin is included in [`ObservedUtilityPlugins::RealTime`].
///
/// This plugin is meant for real-time games, but might be useful for turn-based games as well.