Expand description
Bonsai - Behavior Tree
You can serialize the behavior tree using Serde, Ron and graphviz
A Behavior Tree (BT) is a data structure in which we can set the rules of how certain behavior’s can occur, and the order in which they would execute. BTs are a very efficient way of creating complex systems that are both modular and reactive. These properties are crucial in many applications, which has led to the spread of BT from computer game programming to many branches of AI and Robotics.
§How to use a Behavior tree?
A Behavior Tree forms a tree structure where each node represents a process.
When the process terminates, it signals Success
or Failure
. This can then
be used by the parent node to select the next process.
A signal Running
is used to tell the process is not done yet.
For example, if you have a state A
and a state B
:
- Move from state
A
to stateB
ifA
succeeds:Sequence([A, B])
- Try
A
first and then tryB
ifA
fails:Select([A, B])
- If
condition
succeedes doA
, else doB
:If(condition, A, B)
- If
A
succeeds, return failure (and vice-versa):Invert(A)
- Do
B
repeatedly whileA
runs:While(A, [B])
- Do
A
,B
forever:While(WaitForever, [A, B])
- Run
A
andB
in parallell and wait for both to succeed:WhenAll([A, B])
- Run
A
andB
in parallell and wait for any to succeed:WhenAny([A, B])
- Run
A
andB
in parallell, butA
has to succeed beforeB
:After([A, B])
See the Behavior
enum for more information.
§Example of use
This is a simple example with two possible Actions: Increment a number, Decrement a number. We
construct a BT where we increment a number twice, one second apart. Then wait 0.5 seconds before we
then decrement the same number again. Additionally we use a Blackboard to store/persist the immediate
state of the number accessed by the key count
.
use bonsai_bt::{Event, Success, UpdateArgs, BT};
use std::collections::HashMap;
// Some test actions.
#[derive(Clone, Debug, Copy)]
pub enum Actions {
///! Increment accumulator.
Inc,
///! Decrement accumulator.
Dec,
}
// A test state machine that can increment and decrement.
fn tick(mut acc: i32, dt: f64, bt: &mut BT<Actions, HashMap<String, i32>>) -> i32 {
let e: Event = UpdateArgs { dt }.into();
let (_status, _dt) = bt.tick(&e, &mut |args, blackboard| match *args.action {
Actions::Inc => {
acc += 1;
(Success, args.dt)
}
Actions::Dec => {
acc -= 1;
(Success, args.dt)
}
});
// update counter in blackboard
let bb = bt.get_blackboard();
bb.get_db()
.entry("count".to_string())
.and_modify(|count| *count = acc)
.or_insert(0)
.to_owned();
acc
}
fn main() {
use crate::Actions::{Inc, Dec};
use std::collections::HashMap;
use bonsai_bt::{Action, Sequence, Wait};
// create the behavior
let behavior = Sequence(vec![
Wait(1.0),
Action(Inc),
Wait(1.0),
Action(Inc),
Wait(0.5),
Action(Dec),
]);
// you have to initialize a blackboard even though you're
// not necessarily using it for storage
let mut blackboard: HashMap<String, i32> = HashMap::new();
// instantiate the bt
let mut bt = BT::new(behavior, blackboard);
let a: i32 = 0;
let a = tick(a, 0.5, &mut bt); // have bt advance 0.5 seconds into the future
assert_eq!(a, 0);
let a = tick(a, 0.5, &mut bt); // have bt advance another 0.5 seconds into the future
assert_eq!(a, 1);
let a = tick(a, 0.5, &mut bt);
assert_eq!(a, 1);
let a = tick(a, 0.5, &mut bt);
assert_eq!(a, 2);
let a = tick(a, 0.5, &mut bt);
assert_eq!(a, 1);
let bb = bt.get_blackboard();
let count = bb.get_db().get("count").unwrap();
assert_eq!(*count, 1);
// if the behavior tree concludes (reaches a steady state)
// you can reset the tree back to it's initial state at t=0.0
bt.reset_bt();
}
Re-exports§
pub use behavior::Behavior::Action;
pub use behavior::Behavior::After;
pub use behavior::Behavior::AlwaysSucceed;
pub use behavior::Behavior::If;
pub use behavior::Behavior::Invert;
pub use behavior::Behavior::Select;
pub use behavior::Behavior::Sequence;
pub use behavior::Behavior::Wait;
pub use behavior::Behavior::WaitForever;
pub use behavior::Behavior::WhenAll;
pub use behavior::Behavior::WhenAny;
pub use behavior::Behavior::While;
pub use behavior::Behavior::WhileAll;
pub use status::Status::Failure;
pub use status::Status::Running;
pub use status::Status::Success;
Structs§
- The arguments in the action callback.
- The BT struct contains a compiled (immutable) version of the behavior and a blackboard key/value storage
- A monotonic clock/timer that can be used to keep track of the time increments (delta time) between tick/tree traversals and the total duration since the behavior tree was first invoked/traversed
- Update arguments, such as delta time in seconds. To move the behavior tree forward in time it must be ticked on each iteration of the game/application loop.
Enums§
- Describes a behavior.
- Models all events.
- Keeps track of a behavior.
- The result of a behavior or action.
Constants§
- The action is still running, and thus the action consumes all the remaining delta time for the tick
Traits§
- When the application state should be updated.