mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
docs for behavior tree
This commit is contained in:
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user