docs for behavior tree

This commit is contained in:
Dmitry
2021-08-08 15:57:45 +03:00
parent c4b942384a
commit 36c11dbb56
3 changed files with 62 additions and 7 deletions
+19
View File
@@ -1,11 +1,25 @@
//! Composite node is a container for children nodes. Composite node could be either
//! `Sequence` or `Selector`. `Sequence` node will execute children nodes consecutively
//! until `Status::Failure` is returned from any descendant node. In other words `Sequence`
//! implement AND logical function. `Selector` node will execute children until `Status::Success`
//! is returned from any descendant node. In other worlds `Selector` implement OR logical
//! function.
use crate::{
core::{pool::Handle, visitor::prelude::*},
utils::behavior::{BehaviorNode, BehaviorTree},
};
/// Defines exact behavior of the composite node.
#[derive(Debug, PartialEq, Visit)]
pub enum CompositeNodeKind {
/// `Sequence` node will execute children nodes consecutively
/// until `Status::Failure` is returned from any descendant node. In other words `Sequence`
/// implement AND logical function.
Sequence,
/// `Selector` node will execute children until `Status::Success`
/// is returned from any descendant node. In other worlds `Selector` implement OR logical
/// function.
Selector,
}
@@ -15,9 +29,12 @@ impl Default for CompositeNodeKind {
}
}
/// See module docs.
#[derive(Debug, PartialEq, Visit)]
pub struct CompositeNode<B> {
/// A set of children.
pub children: Vec<Handle<BehaviorNode<B>>>,
/// Current kind of the node.
pub kind: CompositeNodeKind,
}
@@ -31,10 +48,12 @@ impl<B> Default for CompositeNode<B> {
}
impl<B> CompositeNode<B> {
/// Creates new composite node of given kind and set of children nodes.
pub fn new(kind: CompositeNodeKind, children: Vec<Handle<BehaviorNode<B>>>) -> Self {
Self { children, kind }
}
/// Adds self to the tree and return handle to self.
pub fn add(self, tree: &mut BehaviorTree<B>) -> Handle<BehaviorNode<B>> {
tree.add_node(BehaviorNode::Composite(self))
}
+7
View File
@@ -1,11 +1,16 @@
//! Leaf is a "final" node of a behavior tree. It contains user-defined action which
//! is able to mutate given context.
use crate::{
core::{pool::Handle, visitor::prelude::*},
utils::behavior::{BehaviorNode, BehaviorTree},
};
use std::cell::RefCell;
/// See module docs.
#[derive(Debug, PartialEq, Visit)]
pub struct LeafNode<B> {
/// User-defined behavior.
pub behavior: Option<RefCell<B>>,
}
@@ -16,12 +21,14 @@ impl<B> Default for LeafNode<B> {
}
impl<B> LeafNode<B> {
/// Creates new leaf node with given action.
pub fn new(behavior: B) -> Self {
Self {
behavior: Some(RefCell::new(behavior)),
}
}
/// Adds self to given behavior tree and returns handle to self.
pub fn add(self, tree: &mut BehaviorTree<B>) -> Handle<BehaviorNode<B>> {
tree.add_node(BehaviorNode::Leaf(self))
}
+36 -7
View File
@@ -1,4 +1,17 @@
#![allow(missing_docs)] // TODO
#![warn(missing_docs)]
//! Everything related to AI behavior and behavior trees.
//!
//! Behavior trees are simple but very powerful mechanism to implement artificial intelligence for
//! games. The main concept is in its name. Tree is a set of connected nodes, where each node could
//! have single parent and zero or more children nodes. Execution path of the tree is defined by the
//! actions of the nodes. Behavior tree has a set of hard coded nodes as well as leaf nodes with
//! user-defined logic. Hard coded nodes are: Sequence, Selector, Leaf. Leaf is special - it has
//! custom method `tick` that can contain any logic you want.
//!
//! For more info see:
//! - [Wikipedia article](https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control)
//! - [Gamasutra](https://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php)
use crate::{
core::{
@@ -15,18 +28,28 @@ use std::fmt::Debug;
pub mod composite;
pub mod leaf;
/// Status of execution of behavior tree node.
pub enum Status {
/// Action was successful.
Success,
/// Failed to perform an action.
Failure,
/// Need another iteration to perform an action.
Running,
}
/// A trait for user-defined actions for behavior tree.
pub trait Behavior: Visit + Default + PartialEq + Debug {
/// A context in which the behavior will be performed.
type Context;
/// A function that will be called each frame depending on
/// the current execution path of the behavior tree it belongs
/// to.
fn tick(&mut self, context: &mut Self::Context) -> Status;
}
/// Root node of the tree.
#[derive(Debug, PartialEq, Visit)]
pub struct RootNode<B> {
child: Handle<BehaviorNode<B>>,
@@ -40,11 +63,16 @@ impl<B> Default for RootNode<B> {
}
}
/// Possible variations of behavior nodes.
#[derive(Debug, PartialEq, Visit)]
pub enum BehaviorNode<B> {
#[doc(hidden)]
Unknown,
/// Root node of the tree.
Root(RootNode<B>),
/// Composite (sequence or selector) node of the tree.
Composite(CompositeNode<B>),
/// A node with custom logic.
Leaf(LeafNode<B>),
}
@@ -54,6 +82,7 @@ impl<B> Default for BehaviorNode<B> {
}
}
/// See module docs.
#[derive(Debug, PartialEq, Visit)]
pub struct BehaviorTree<B> {
nodes: Pool<BehaviorNode<B>>,
@@ -70,6 +99,7 @@ impl<B> Default for BehaviorTree<B> {
}
impl<B> BehaviorTree<B> {
/// Creates new behavior tree with single root node.
pub fn new() -> Self {
let mut nodes = Pool::new();
let root = nodes.spawn(BehaviorNode::Root(RootNode {
@@ -78,10 +108,12 @@ impl<B> BehaviorTree<B> {
Self { nodes, root }
}
/// Adds a node to the tree, returns its handle.
pub fn add_node(&mut self, node: BehaviorNode<B>) -> Handle<BehaviorNode<B>> {
self.nodes.spawn(node)
}
/// Sets entry nodes of the tree. Execution will start from this node.
pub fn set_entry_node(&mut self, entry: Handle<BehaviorNode<B>>) {
if let BehaviorNode::Root(root) = &mut self.nodes[self.root] {
root.child = entry;
@@ -140,6 +172,7 @@ impl<B> BehaviorTree<B> {
}
}
/// Performs a single update tick with given context.
pub fn tick<Ctx>(&self, context: &mut Ctx) -> Status
where
B: Behavior<Context = Ctx>,
@@ -150,19 +183,15 @@ impl<B> BehaviorTree<B> {
#[cfg(test)]
mod test {
use crate::core::futures::executor::block_on;
use crate::{
core::visitor::prelude::*,
core::{futures::executor::block_on, visitor::prelude::*},
utils::behavior::{
composite::{CompositeNode, CompositeNodeKind},
leaf::LeafNode,
Behavior, BehaviorTree, Status,
},
};
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::{env, fs::File, io::Write, path::PathBuf};
#[derive(Debug, PartialEq, Default, Visit)]
struct WalkAction;