fyrox_impl/utils/behavior/
mod.rs1#![warn(missing_docs)]
22
23use crate::{
37 core::{
38 pool::{Handle, Pool},
39 visitor::prelude::*,
40 },
41 utils::behavior::{
42 composite::{CompositeNode, CompositeNodeKind},
43 inverter::Inverter,
44 leaf::LeafNode,
45 },
46};
47use std::{
48 fmt::Debug,
49 ops::{Index, IndexMut},
50};
51
52pub mod composite;
53pub mod inverter;
54pub mod leaf;
55
56pub enum Status {
58 Success,
60 Failure,
62 Running,
64}
65
66pub trait Behavior<'a>: Visit + Default + PartialEq + Debug + Clone {
68 type Context;
70
71 fn tick(&mut self, context: &mut Self::Context) -> Status;
75}
76
77#[derive(Debug, PartialEq, Visit, Eq, Clone)]
79pub struct RootNode<B>
80where
81 B: Clone,
82{
83 child: Handle<BehaviorNode<B>>,
84}
85
86impl<B> Default for RootNode<B>
87where
88 B: Clone,
89{
90 fn default() -> Self {
91 Self {
92 child: Default::default(),
93 }
94 }
95}
96
97#[derive(Debug, PartialEq, Visit, Eq, Clone)]
99pub enum BehaviorNode<B>
100where
101 B: Clone,
102{
103 #[doc(hidden)]
104 Unknown,
105 Root(RootNode<B>),
107 Composite(CompositeNode<B>),
109 Leaf(LeafNode<B>),
111 Inverter(Inverter<B>),
114}
115
116impl<B> Default for BehaviorNode<B>
117where
118 B: Clone,
119{
120 fn default() -> Self {
121 Self::Unknown
122 }
123}
124
125#[derive(Debug, PartialEq, Visit, Clone)]
127pub struct BehaviorTree<B>
128where
129 B: Clone,
130{
131 nodes: Pool<BehaviorNode<B>>,
132 root: Handle<BehaviorNode<B>>,
133}
134
135impl<B> Default for BehaviorTree<B>
136where
137 B: Clone + 'static,
138{
139 fn default() -> Self {
140 Self {
141 nodes: Default::default(),
142 root: Default::default(),
143 }
144 }
145}
146
147impl<B> BehaviorTree<B>
148where
149 B: Clone + 'static,
150{
151 pub fn new() -> Self {
153 let mut nodes = Pool::new();
154 let root = nodes.spawn(BehaviorNode::Root(RootNode {
155 child: Default::default(),
156 }));
157 Self { nodes, root }
158 }
159
160 pub fn add_node(&mut self, node: BehaviorNode<B>) -> Handle<BehaviorNode<B>> {
162 self.nodes.spawn(node)
163 }
164
165 pub fn set_entry_node(&mut self, entry: Handle<BehaviorNode<B>>) {
167 if let BehaviorNode::Root(root) = &mut self.nodes[self.root] {
168 root.child = entry;
169 } else {
170 unreachable!("must be root")
171 }
172 }
173
174 fn tick_recursive<'a, Ctx>(&self, handle: Handle<BehaviorNode<B>>, context: &mut Ctx) -> Status
175 where
176 B: Behavior<'a, Context = Ctx>,
177 {
178 match self.nodes[handle] {
179 BehaviorNode::Root(ref root) => {
180 if root.child.is_some() {
181 self.tick_recursive(root.child, context)
182 } else {
183 Status::Success
184 }
185 }
186 BehaviorNode::Composite(ref composite) => match composite.kind {
187 CompositeNodeKind::Sequence => {
188 let mut all_succeeded = true;
189 for child in composite.children.iter() {
190 match self.tick_recursive(*child, context) {
191 Status::Failure => {
192 all_succeeded = false;
193 break;
194 }
195 Status::Running => {
196 return Status::Running;
197 }
198 _ => (),
199 }
200 }
201 if all_succeeded {
202 Status::Success
203 } else {
204 Status::Failure
205 }
206 }
207 CompositeNodeKind::Selector => {
208 for child in composite.children.iter() {
209 match self.tick_recursive(*child, context) {
210 Status::Success => return Status::Success,
211 Status::Running => return Status::Running,
212 _ => (),
213 }
214 }
215 Status::Failure
216 }
217 },
218 BehaviorNode::Leaf(ref leaf) => {
219 leaf.behavior.as_ref().unwrap().borrow_mut().tick(context)
220 }
221 BehaviorNode::Inverter(ref inverter) => {
222 match self.tick_recursive(inverter.child, context) {
223 Status::Success => Status::Failure,
224 Status::Failure => Status::Success,
225 Status::Running => Status::Running,
226 }
227 }
228 BehaviorNode::Unknown => {
229 unreachable!()
230 }
231 }
232 }
233
234 pub fn node(&self, handle: Handle<BehaviorNode<B>>) -> Option<&BehaviorNode<B>> {
236 self.nodes.try_borrow(handle)
237 }
238
239 pub fn node_mut(&mut self, handle: Handle<BehaviorNode<B>>) -> Option<&mut BehaviorNode<B>> {
241 self.nodes.try_borrow_mut(handle)
242 }
243
244 pub fn tick<'a, Ctx>(&self, context: &mut Ctx) -> Status
246 where
247 B: Behavior<'a, Context = Ctx>,
248 {
249 self.tick_recursive(self.root, context)
250 }
251}
252
253impl<B: Clone + 'static> Index<Handle<BehaviorNode<B>>> for BehaviorTree<B> {
254 type Output = BehaviorNode<B>;
255
256 fn index(&self, index: Handle<BehaviorNode<B>>) -> &Self::Output {
257 &self.nodes[index]
258 }
259}
260
261impl<B: Clone + 'static> IndexMut<Handle<BehaviorNode<B>>> for BehaviorTree<B> {
262 fn index_mut(&mut self, index: Handle<BehaviorNode<B>>) -> &mut Self::Output {
263 &mut self.nodes[index]
264 }
265}
266
267pub fn sequence<B, const N: usize>(
269 children: [Handle<BehaviorNode<B>>; N],
270 tree: &mut BehaviorTree<B>,
271) -> Handle<BehaviorNode<B>>
272where
273 B: Clone + 'static,
274{
275 CompositeNode::new_sequence(children.to_vec()).add_to(tree)
276}
277
278pub fn selector<B, const N: usize>(
280 children: [Handle<BehaviorNode<B>>; N],
281 tree: &mut BehaviorTree<B>,
282) -> Handle<BehaviorNode<B>>
283where
284 B: Clone + 'static,
285{
286 CompositeNode::new_selector(children.to_vec()).add_to(tree)
287}
288
289pub fn leaf<B>(behavior: B, tree: &mut BehaviorTree<B>) -> Handle<BehaviorNode<B>>
291where
292 B: Clone + 'static,
293{
294 LeafNode::new(behavior).add_to(tree)
295}
296
297pub fn inverter<B>(
299 child: Handle<BehaviorNode<B>>,
300 tree: &mut BehaviorTree<B>,
301) -> Handle<BehaviorNode<B>>
302where
303 B: Clone + 'static,
304{
305 Inverter::new(child).add_to(tree)
306}
307
308#[cfg(test)]
309mod test {
310 use crate::{
311 core::{futures::executor::block_on, visitor::prelude::*},
312 utils::behavior::{
313 composite::{CompositeNode, CompositeNodeKind},
314 leaf::LeafNode,
315 Behavior, BehaviorTree, Status,
316 },
317 };
318 use std::{env, fs::File, io::Write, path::PathBuf};
319
320 #[derive(Debug, PartialEq, Default, Visit, Clone)]
321 struct WalkAction;
322
323 impl Behavior<'_> for WalkAction {
324 type Context = Environment;
325
326 fn tick(&mut self, context: &mut Self::Context) -> Status {
327 if context.distance_to_door <= 0.0 {
328 Status::Success
329 } else {
330 context.distance_to_door -= 0.1;
331 println!(
332 "Approaching door, remaining distance: {}",
333 context.distance_to_door
334 );
335 Status::Running
336 }
337 }
338 }
339
340 #[derive(Debug, PartialEq, Default, Visit, Clone)]
341 struct OpenDoorAction;
342
343 impl Behavior<'_> for OpenDoorAction {
344 type Context = Environment;
345
346 fn tick(&mut self, context: &mut Self::Context) -> Status {
347 if !context.door_opened {
348 context.door_opened = true;
349 println!("Door was opened!");
350 }
351 Status::Success
352 }
353 }
354
355 #[derive(Debug, PartialEq, Default, Visit, Clone)]
356 struct StepThroughAction;
357
358 impl Behavior<'_> for StepThroughAction {
359 type Context = Environment;
360
361 fn tick(&mut self, context: &mut Self::Context) -> Status {
362 if context.distance_to_door < -1.0 {
363 Status::Success
364 } else {
365 context.distance_to_door -= 0.1;
366 println!(
367 "Stepping through doorway, remaining distance: {}",
368 -1.0 - context.distance_to_door
369 );
370 Status::Running
371 }
372 }
373 }
374
375 #[derive(Debug, PartialEq, Default, Visit, Clone)]
376 struct CloseDoorAction;
377
378 impl Behavior<'_> for CloseDoorAction {
379 type Context = Environment;
380
381 fn tick(&mut self, context: &mut Self::Context) -> Status {
382 if context.door_opened {
383 context.door_opened = false;
384 context.done = true;
385 println!("Door was closed");
386 }
387 Status::Success
388 }
389 }
390
391 #[derive(Debug, PartialEq, Visit, Clone)]
392 enum BotBehavior {
393 None,
394 Walk(WalkAction),
395 OpenDoor(OpenDoorAction),
396 StepThrough(StepThroughAction),
397 CloseDoor(CloseDoorAction),
398 }
399
400 impl Default for BotBehavior {
401 fn default() -> Self {
402 Self::None
403 }
404 }
405
406 #[derive(Default, Visit)]
407 struct Environment {
408 distance_to_door: f32,
411 door_opened: bool,
412 done: bool,
413 }
414
415 impl Behavior<'_> for BotBehavior {
416 type Context = Environment;
417
418 fn tick(&mut self, context: &mut Self::Context) -> Status {
419 match self {
420 BotBehavior::None => unreachable!(),
421 BotBehavior::Walk(v) => v.tick(context),
422 BotBehavior::OpenDoor(v) => v.tick(context),
423 BotBehavior::StepThrough(v) => v.tick(context),
424 BotBehavior::CloseDoor(v) => v.tick(context),
425 }
426 }
427 }
428
429 fn create_tree() -> BehaviorTree<BotBehavior> {
430 let mut tree = BehaviorTree::new();
431
432 let entry = CompositeNode::new(
433 CompositeNodeKind::Sequence,
434 vec![
435 LeafNode::new(BotBehavior::Walk(WalkAction)).add_to(&mut tree),
436 LeafNode::new(BotBehavior::OpenDoor(OpenDoorAction)).add_to(&mut tree),
437 LeafNode::new(BotBehavior::StepThrough(StepThroughAction)).add_to(&mut tree),
438 LeafNode::new(BotBehavior::CloseDoor(CloseDoorAction)).add_to(&mut tree),
439 ],
440 )
441 .add_to(&mut tree);
442
443 tree.set_entry_node(entry);
444
445 tree
446 }
447
448 #[test]
449 fn test_behavior() {
450 let tree = create_tree();
451
452 let mut ctx = Environment {
453 distance_to_door: 3.0,
454 door_opened: false,
455 done: false,
456 };
457
458 while !ctx.done {
459 tree.tick(&mut ctx);
460 }
461 }
462
463 #[test]
464 fn test_behavior_save_load() {
465 let (bin, txt) = {
466 let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
467 let root = PathBuf::from(manifest_dir).join("test_output");
468 if !root.exists() {
469 std::fs::create_dir(&root).unwrap();
470 }
471 (
472 root.join(format!("{}.bin", "behavior_save_load")),
473 root.join(format!("{}.txt", "behavior_save_load")),
474 )
475 };
476
477 let mut saved_tree = create_tree();
479 let mut visitor = Visitor::new();
480 saved_tree.visit("Tree", &mut visitor).unwrap();
481 visitor.save_binary(bin.clone()).unwrap();
482 let mut file = File::create(txt).unwrap();
483 file.write_all(visitor.save_text().as_bytes()).unwrap();
484
485 let mut visitor = block_on(Visitor::load_binary(bin)).unwrap();
487 let mut loaded_tree = BehaviorTree::<BotBehavior>::default();
488 loaded_tree.visit("Tree", &mut visitor).unwrap();
489
490 assert_eq!(saved_tree, loaded_tree);
491 }
492}