Tiny Behavior is a small, easy to learn and use, header only Behavior Tree library writen in C++.
Its easy, look, there is a simple example:
#include <iostream>
#include "TinyBehavior.h"
int main(int argc, char* argv[]) {
// all data would be local if we provide appropriate size to the builder
const size_t treeSize = sizeof(tb::ParallelSequence) + sizeof(tb::Action) * 4 + sizeof(tb::Failer) + sizeof(tb::Condition) + sizeof(tb::Limiter) + sizeof(ActionNode1);
tb::BehaviorTreeBuilder builder(treeSize);
tb::BehaviorTree* tree;
tree = builder.parallel()
.action([] (tb::Node* const& currentNode, void* const& data = nullptr) {
std::cout << '\n';
std::cout << "Im an action in parallel node!" << "\n";
return tb::Node::status::success;
})
.failer()
.action([] (tb::Node* const& currentNode, void* const& data = nullptr) {
std::cout << "Im another action in parallel node!" << "\n";
return tb::Node::status::success;
})
.condition([] (tb::Node* const& currentNode, void* const& data = nullptr) {
std::cout << "Some condition before action!" << "\n";
return true;
})
.action([] (tb::Node* const& currentNode, void* const& data = nullptr) {
std::cout << "Im an action in the condition!" << "\n";
return tb::Node::status::running;
})
.limiter(5)
.action([] (tb::Node* const& currentNode, void* const& data = nullptr) {
std::cout << "Im an action that succeds or run only 5 times" << "\n";
return tb::Node::status::success;
})
// ... and others type of nodes, you can read about them below
.end() // parallel needs to be end
.build();
tree.print(" "); // for debugging
tb::Node* running = nullptr; // for optimisation purpose you can take currently running action node
for (size_t i = 0; i < 6; ++i) {
tree->update(
nullptr, // user data
&running
); // use
}
if (running != nullptr) running->update();
// ...
delete tree; // dont forget to delete tree, it deletes all nodes in that tree too
}
You can even make your own node:
class Idle : public tb::Leaf {
public:
Idle(bool* enemyInSight) : Leaf(), enemyInSight(enemyInSight) {}
// main function
tb::Node::status update(void* const& data = nullptr, tb::Node** runningPtr = nullptr) override {
(void)runningPtr; // use it when you need a pointer to running node
if (*enemyInSight) return Node::Status::Success;
std::cout << "Im waiting!" << "\n";
return Node::Status::Failure;
}
// std::string toString() const {} - can be overriden
// void print(const std::string &indent) const {} - can be overriden
private:
bool* enemyInSight;
};
and use it in your code:
// ...
Idle* idle = nullptr; // here would be pointer to your node
// ...
tree = builder
// ...
.leaf<Idle>(&idle, &someBoolPointer)
// ...
.build();
tree.update();
// ...
delete tree; // not needs to delete idle
All information about making your own nodes is in paragraph Inheritance.
BehaviorTreeBuilder class methods:
sequence()
- updates all nodes until faces Status::Failure
or Status::Running
selector()
- updates all nodes until faces Status::Success
or Status::Running
parallel(minSuccess, minFail)
- updates all nodes, return Status::Success
if totalSuccess
>= minSuccess
or Status::Failure
if totalFails
>= minFail
else Status::Running
memSelector()
- updates all nodes until faces Status::Success
or Status::Running
, next updation will start from that node
memSequence()
- updates all nodes until faces Status::Failure
or Status::Running
, next updation will start from that node
random(seed)
- updates random (depends on seed) node
whiledo(predicate)
- updates all nodes while condition == true
, returns Status::Running
in this case, if condition == false
does nothing and returns Status::Failure
(Status::Success
is true
, Status::Failure
is false
)
conjunction()
- Status first && Status second
disjunction()
- Status first || Status second
equality()
- Status first == Status second
implication()
- Status first -> Status second (!(Status first) || Status second) (Status::Running
= Status::Failure
)
ifelse(predicate)
- if contidion == true
updates first, else second
inverter()
- inverts Status::Success
and Status::Failure
, Status::Running
ignored
repeater(limit)
- returns Status::Running
limit
times, then return node status and resets
limiter(limit)
- returns decorator's child status limit
times, then return Status::Failure
untilFail()
- returns only Status::Running
or Status::Failure
untilSuccess()
- returns only Status::Running
or Status::Success
failer()
- returns only Status::Failure
succeeder()
- returns only Status::Success
condition(predicate)
- updates child if predicate == true
else returns Status::Failure
action(action)
- userdefined action function, must return statuses
end()
- use it after every Compositor or Binary nodes
add(node)
- adds nodes to the current tree, NOTE: adding trees is under construction
leaf(arguments)
- create userdefined action node
build()
- does some postworks and returns BehaviorTree
pointer
debug(string)
- just prints the string
setDebugCallback(callback)
- set callback function for the error strings
Every nodes in TinyBehavior has the virtual destructor, that means technicaly you can inherit every class, but if you want make a new node type (besides Compositor, Decorator, Binary, Action and Tree) you must implement a static method constexpr static uint32_t getType() {}
for the template method is()
in Node class and override add()
or add a new method to the BehaviorTreeBuilder (which has the virtual destructor too).
About the main types:
addChild(node)
- adds the child to the node vector
hasChildren()
- is the node vector empty?
getIndex()
- get the current index of node
children
- nodes vector
index
- current index
setChild()
- sets child
hasChild()
- child != nullptr
child
- decorator child
setFirstChild(node)
- sets first child
setSecondChild(node)
- sets second child
setChild(index, node)
- sets child using index (0 or 1)
hasFirstChild()
- is first child != nullptr
hasSecondChild()
- is second child != nullptr
nodes
- pair of childs
update(data, runningNodePtr)
, toString()
and print(indent)
can be overriden from any class. Check source code for more information
Perfectly hided in example folder, provided with Makefile
- Userdefined decorator/compositor/binary node create method
- Delete repeater?
- Tests
- Benchmarks
- Multithreading support
- Multithreading examples
MIT