Skip to main content

fyrox_impl/utils/behavior/
mod.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21#![warn(missing_docs)]
22
23//! Everything related to AI behavior and behavior trees.
24//!
25//! Behavior trees are simple but very powerful mechanism to implement artificial intelligence for
26//! games. The main concept is in its name. Tree is a set of connected nodes, where each node could
27//! have single parent and zero or more children nodes. Execution path of the tree is defined by the
28//! actions of the nodes. Behavior tree has a set of hard coded nodes as well as leaf nodes with
29//! user-defined logic. Hard coded nodes are: Sequence, Selector, Leaf. Leaf is special - it has
30//! custom method `tick` that can contain any logic you want.
31//!
32//! For more info see:
33//! - [Wikipedia article](https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control))
34//! - [Gamasutra](https://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php)
35
36use crate::plugin::error::GameError;
37use crate::{
38    core::{
39        pool::{Handle, Pool},
40        visitor::prelude::*,
41    },
42    utils::behavior::{
43        composite::{CompositeNode, CompositeNodeKind},
44        inverter::Inverter,
45        leaf::LeafNode,
46    },
47};
48use fyrox_core::pool::PoolError;
49use std::{
50    fmt::Debug,
51    ops::{Index, IndexMut},
52};
53
54pub mod composite;
55pub mod inverter;
56pub mod leaf;
57
58/// An alias for `Result<Status, GameError>`
59pub type BehaviorResult = Result<Status, GameError>;
60
61/// Status of execution of behavior tree node.
62pub enum Status {
63    /// Action was successful.
64    Success,
65    /// Failed to perform an action.
66    Failure,
67    /// Need another iteration to perform an action.
68    Running,
69}
70
71/// Base trait for all behaviors. This trait has auto-impl.
72pub trait BaseBehavior: Visit + Default + PartialEq + Debug + Clone + 'static {}
73impl<T: Visit + Default + PartialEq + Debug + Clone + 'static> BaseBehavior for T {}
74
75/// A trait for user-defined actions for behavior tree.
76pub trait Behavior<'a>: BaseBehavior {
77    /// A context in which the behavior will be performed.
78    type Context;
79
80    /// A function that will be called each frame depending on
81    /// the current execution path of the behavior tree it belongs
82    /// to.
83    fn tick(&mut self, context: &mut Self::Context) -> Result<Status, GameError>;
84}
85
86/// Root node of the tree.
87#[derive(Debug, PartialEq, Visit, Eq, Clone)]
88pub struct RootNode<B>
89where
90    B: BaseBehavior,
91{
92    child: Handle<BehaviorNode<B>>,
93}
94
95impl<B> Default for RootNode<B>
96where
97    B: BaseBehavior,
98{
99    fn default() -> Self {
100        Self {
101            child: Default::default(),
102        }
103    }
104}
105
106/// Possible variations of behavior nodes.
107#[derive(Debug, PartialEq, Visit, Eq, Clone, Default)]
108pub enum BehaviorNode<B>
109where
110    B: BaseBehavior,
111{
112    #[doc(hidden)]
113    #[default]
114    Unknown,
115    /// Root node of the tree.
116    Root(RootNode<B>),
117    /// Composite (sequence or selector) node of the tree.
118    Composite(CompositeNode<B>),
119    /// A node with custom logic.
120    Leaf(LeafNode<B>),
121    /// A node, that inverts its child state ([`Status::Failure`] becomes [`Status::Success`] and vice versa, [`Status::Running`] remains
122    /// unchanged)
123    Inverter(Inverter<B>),
124}
125
126/// See module docs.
127#[derive(Debug, PartialEq, Visit, Clone)]
128pub struct BehaviorTree<B>
129where
130    B: BaseBehavior,
131{
132    nodes: Pool<BehaviorNode<B>>,
133    root: Handle<BehaviorNode<B>>,
134}
135
136impl<B> Default for BehaviorTree<B>
137where
138    B: BaseBehavior,
139{
140    fn default() -> Self {
141        Self {
142            nodes: Default::default(),
143            root: Default::default(),
144        }
145    }
146}
147
148impl<B> BehaviorTree<B>
149where
150    B: BaseBehavior,
151{
152    /// Creates new behavior tree with single root node.
153    pub fn new() -> Self {
154        let mut nodes = Pool::new();
155        let root = nodes.spawn(BehaviorNode::Root(RootNode {
156            child: Default::default(),
157        }));
158        Self { nodes, root }
159    }
160
161    /// Adds a node to the tree, returns its handle.
162    pub fn add_node(&mut self, node: BehaviorNode<B>) -> Handle<BehaviorNode<B>> {
163        self.nodes.spawn(node)
164    }
165
166    /// Sets entry nodes of the tree. Execution will start from this node.
167    pub fn set_entry_node(&mut self, entry: Handle<BehaviorNode<B>>) {
168        if let BehaviorNode::Root(root) = &mut self.nodes[self.root] {
169            root.child = entry;
170        } else {
171            unreachable!("must be root")
172        }
173    }
174
175    fn tick_recursive<'a, Ctx>(
176        &self,
177        handle: Handle<BehaviorNode<B>>,
178        context: &mut Ctx,
179    ) -> Result<Status, GameError>
180    where
181        B: Behavior<'a, Context = Ctx>,
182    {
183        match self.nodes[handle] {
184            BehaviorNode::Root(ref root) => {
185                if root.child.is_some() {
186                    self.tick_recursive(root.child, context)
187                } else {
188                    Ok(Status::Success)
189                }
190            }
191            BehaviorNode::Composite(ref composite) => match composite.kind {
192                CompositeNodeKind::Sequence => {
193                    let mut all_succeeded = true;
194                    for child in composite.children.iter() {
195                        match self.tick_recursive(*child, context)? {
196                            Status::Failure => {
197                                all_succeeded = false;
198                                break;
199                            }
200                            Status::Running => {
201                                return Ok(Status::Running);
202                            }
203                            _ => (),
204                        }
205                    }
206                    if all_succeeded {
207                        Ok(Status::Success)
208                    } else {
209                        Ok(Status::Failure)
210                    }
211                }
212                CompositeNodeKind::Selector => {
213                    for child in composite.children.iter() {
214                        match self.tick_recursive(*child, context)? {
215                            Status::Success => return Ok(Status::Success),
216                            Status::Running => return Ok(Status::Running),
217                            _ => (),
218                        }
219                    }
220                    Ok(Status::Failure)
221                }
222            },
223            BehaviorNode::Leaf(ref leaf) => {
224                leaf.behavior.as_ref().unwrap().borrow_mut().tick(context)
225            }
226            BehaviorNode::Inverter(ref inverter) => {
227                match self.tick_recursive(inverter.child, context)? {
228                    Status::Success => Ok(Status::Failure),
229                    Status::Failure => Ok(Status::Success),
230                    Status::Running => Ok(Status::Running),
231                }
232            }
233            BehaviorNode::Unknown => {
234                unreachable!()
235            }
236        }
237    }
238
239    /// Tries to get a shared reference to a node by given handle.
240    pub fn node(&self, handle: Handle<BehaviorNode<B>>) -> Result<&BehaviorNode<B>, PoolError> {
241        self.nodes.try_borrow(handle)
242    }
243
244    /// Tries to get a mutable reference to a node by given handle.
245    pub fn node_mut(
246        &mut self,
247        handle: Handle<BehaviorNode<B>>,
248    ) -> Result<&mut BehaviorNode<B>, PoolError> {
249        self.nodes.try_borrow_mut(handle)
250    }
251
252    /// Performs a single update tick with given context.
253    pub fn tick<'a, Ctx>(&self, context: &mut Ctx) -> Result<Status, GameError>
254    where
255        B: Behavior<'a, Context = Ctx>,
256    {
257        self.tick_recursive(self.root, context)
258    }
259}
260
261impl<B: BaseBehavior> Index<Handle<BehaviorNode<B>>> for BehaviorTree<B> {
262    type Output = BehaviorNode<B>;
263
264    fn index(&self, index: Handle<BehaviorNode<B>>) -> &Self::Output {
265        &self.nodes[index]
266    }
267}
268
269impl<B: BaseBehavior> IndexMut<Handle<BehaviorNode<B>>> for BehaviorTree<B> {
270    fn index_mut(&mut self, index: Handle<BehaviorNode<B>>) -> &mut Self::Output {
271        &mut self.nodes[index]
272    }
273}
274
275/// Creates a new sequence.
276pub fn sequence<B, const N: usize>(
277    children: [Handle<BehaviorNode<B>>; N],
278    tree: &mut BehaviorTree<B>,
279) -> Handle<BehaviorNode<B>>
280where
281    B: BaseBehavior,
282{
283    CompositeNode::new_sequence(children.to_vec()).add_to(tree)
284}
285
286/// Creates a new selector.
287pub fn selector<B, const N: usize>(
288    children: [Handle<BehaviorNode<B>>; N],
289    tree: &mut BehaviorTree<B>,
290) -> Handle<BehaviorNode<B>>
291where
292    B: BaseBehavior,
293{
294    CompositeNode::new_selector(children.to_vec()).add_to(tree)
295}
296
297/// Creates a new leaf.
298pub fn leaf<B>(behavior: B, tree: &mut BehaviorTree<B>) -> Handle<BehaviorNode<B>>
299where
300    B: BaseBehavior,
301{
302    LeafNode::new(behavior).add_to(tree)
303}
304
305/// Creates a new inverter.
306pub fn inverter<B>(
307    child: Handle<BehaviorNode<B>>,
308    tree: &mut BehaviorTree<B>,
309) -> Handle<BehaviorNode<B>>
310where
311    B: BaseBehavior,
312{
313    Inverter::new(child).add_to(tree)
314}
315
316/// Implements [`Behavior`] trait for the given enumeration and dispatches `tick` call of every
317/// specified variant. This macro is used mostly to reduce boilerplate code
318#[macro_export]
319macro_rules! dispatch_behavior_variants {
320    ($type_name:ident, $context:ty, $($variants:ident),*) => {
321        impl<'a> $crate::utils::behavior::Behavior<'a> for $type_name {
322            type Context = $context;
323
324            fn tick(&mut self, context: &mut Self::Context) -> $crate::utils::behavior::BehaviorResult
325            {
326                match self {
327                    $(
328                        $type_name::$variants(v) => v.tick(context)
329                    ),*
330                }
331            }
332        }
333    };
334}
335
336#[cfg(test)]
337mod test {
338    use crate::utils::behavior::BehaviorResult;
339    use crate::{
340        core::{futures::executor::block_on, visitor::prelude::*},
341        utils::behavior::{leaf, sequence, Behavior, BehaviorTree, Status},
342    };
343    use std::{env, fs::File, io::Write, path::PathBuf};
344
345    #[derive(Visit)]
346    struct Environment {
347        // > 0 - door in front of
348        // < 0 - door is behind
349        distance_to_door: f32,
350        door_opened: bool,
351        done: bool,
352    }
353
354    impl Default for Environment {
355        fn default() -> Self {
356            Self {
357                distance_to_door: 3.0,
358                door_opened: false,
359                done: false,
360            }
361        }
362    }
363
364    #[derive(Debug, PartialEq, Default, Visit, Clone)]
365    struct WalkAction;
366
367    impl Behavior<'_> for WalkAction {
368        type Context = Environment;
369
370        fn tick(&mut self, context: &mut Self::Context) -> BehaviorResult {
371            if context.distance_to_door <= 0.0 {
372                Ok(Status::Success)
373            } else {
374                context.distance_to_door -= 0.1;
375                println!(
376                    "Approaching door, remaining distance: {}",
377                    context.distance_to_door
378                );
379                Ok(Status::Running)
380            }
381        }
382    }
383
384    #[derive(Debug, PartialEq, Default, Visit, Clone)]
385    struct OpenDoorAction;
386
387    impl Behavior<'_> for OpenDoorAction {
388        type Context = Environment;
389
390        fn tick(&mut self, context: &mut Self::Context) -> BehaviorResult {
391            if !context.door_opened {
392                context.door_opened = true;
393                println!("Door was opened!");
394            }
395            Ok(Status::Success)
396        }
397    }
398
399    #[derive(Debug, PartialEq, Default, Visit, Clone)]
400    struct StepThroughAction;
401
402    impl Behavior<'_> for StepThroughAction {
403        type Context = Environment;
404
405        fn tick(&mut self, context: &mut Self::Context) -> BehaviorResult {
406            if context.distance_to_door < -1.0 {
407                Ok(Status::Success)
408            } else {
409                context.distance_to_door -= 0.1;
410                println!(
411                    "Stepping through doorway, remaining distance: {}",
412                    -1.0 - context.distance_to_door
413                );
414                Ok(Status::Running)
415            }
416        }
417    }
418
419    #[derive(Debug, PartialEq, Default, Visit, Clone)]
420    struct CloseDoorAction;
421
422    impl Behavior<'_> for CloseDoorAction {
423        type Context = Environment;
424
425        fn tick(&mut self, context: &mut Self::Context) -> BehaviorResult {
426            if context.door_opened {
427                context.door_opened = false;
428                context.done = true;
429                println!("Door was closed");
430            }
431            Ok(Status::Success)
432        }
433    }
434
435    #[derive(Debug, PartialEq, Visit, Clone)]
436    enum BotAction {
437        Walk(WalkAction),
438        OpenDoor(OpenDoorAction),
439        StepThrough(StepThroughAction),
440        CloseDoor(CloseDoorAction),
441    }
442
443    impl Default for BotAction {
444        fn default() -> Self {
445            Self::Walk(Default::default())
446        }
447    }
448
449    dispatch_behavior_variants!(
450        BotAction,
451        Environment,
452        Walk,
453        OpenDoor,
454        StepThrough,
455        CloseDoor
456    );
457
458    fn create_tree() -> BehaviorTree<BotAction> {
459        let mut tree = BehaviorTree::new();
460
461        let entry = sequence(
462            [
463                leaf(BotAction::Walk(WalkAction), &mut tree),
464                leaf(BotAction::OpenDoor(OpenDoorAction), &mut tree),
465                leaf(BotAction::StepThrough(StepThroughAction), &mut tree),
466                leaf(BotAction::CloseDoor(CloseDoorAction), &mut tree),
467            ],
468            &mut tree,
469        );
470
471        tree.set_entry_node(entry);
472
473        tree
474    }
475
476    #[test]
477    fn test_behavior() {
478        let tree = create_tree();
479
480        let mut ctx = Environment::default();
481
482        while !ctx.done {
483            tree.tick(&mut ctx).unwrap();
484        }
485    }
486
487    #[test]
488    fn test_behavior_save_load() {
489        let (bin, txt) = {
490            let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
491            let root = PathBuf::from(manifest_dir).join("test_output");
492            if !root.exists() {
493                std::fs::create_dir(&root).unwrap();
494            }
495            (
496                root.join(format!("{}.bin", "behavior_save_load")),
497                root.join(format!("{}.txt", "behavior_save_load")),
498            )
499        };
500
501        // Save
502        let mut saved_tree = create_tree();
503        let mut visitor = Visitor::new();
504        saved_tree.visit("Tree", &mut visitor).unwrap();
505        visitor.save_binary_to_file(bin.clone()).unwrap();
506        let mut file = File::create(txt).unwrap();
507        file.write_all(visitor.save_ascii_to_string().as_bytes())
508            .unwrap();
509
510        // Load
511        let mut visitor = block_on(Visitor::load_from_file(bin)).unwrap();
512        let mut loaded_tree = BehaviorTree::<BotAction>::default();
513        loaded_tree.visit("Tree", &mut visitor).unwrap();
514
515        assert_eq!(saved_tree, loaded_tree);
516    }
517}