https://github.com/cryptiklemur/fluent-behavior-tree
Typescript/Javascript behavior tree library with a fluent API
https://github.com/cryptiklemur/fluent-behavior-tree
behavior-tree behavior-trees behaviour-tree behaviour-trees typescript typescript-library
Last synced: 3 months ago
JSON representation
Typescript/Javascript behavior tree library with a fluent API
- Host: GitHub
- URL: https://github.com/cryptiklemur/fluent-behavior-tree
- Owner: cryptiklemur
- License: mit
- Created: 2017-12-05T05:10:01.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2020-09-24T19:52:22.000Z (over 5 years ago)
- Last Synced: 2025-04-14T20:55:34.303Z (about 1 year ago)
- Topics: behavior-tree, behavior-trees, behaviour-tree, behaviour-trees, typescript, typescript-library
- Language: TypeScript
- Homepage:
- Size: 57.6 KB
- Stars: 72
- Watchers: 5
- Forks: 11
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Fluent Behavior Tree
[](https://travis-ci.org/aequasi/fluent-behavior-tree) [](https://badge.fury.io/js/fluent-behavior-tree)
This is a Typescript/Javascript implementation of https://github.com/codecapers/Fluent-Behaviour-Tree
JS/TS behaviour tree library with a fluent API.
For a background and walk-through please see [the accompanying article](http://www.what-could-possibly-go-wrong.com/fluent-behavior-trees-for-ai-and-game-logic/).
## Understanding Behaviour Trees
Here are some resources to help you understand behaviour trees:
- [Behaviour tree (Wikipedia)](https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control))
- [Behavior trees for AI: How they work](http://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php)
- [Understanding Behaviour Trees](http://aigamedev.com/open/article/bt-overview/)
- [Introduction and implementation of Behaviour Trees](http://guineashots.com/2014/07/25/an-introduction-to-behavior-trees-part-1/)
## Installation
Install with npm:
```shell
npm install -s fluent-behavior-tree
```
## Usage
A behavior tree is created through *BehaviorTreeBuilder*. The tree is returned when the *build* function is called.
```
import {BehaviorTreeBuilder, BehaviorTreeStatus, TimeData} from "fluent-behavior-tree";
// ...
const builder = new BehaviorTreeBuilder();
this.tree = builder
.sequence("my-sequence")
.do("action1", async (t) => {
// Action 1.
return BehaviorTreeStatus.Success;
})
.do("action2", async (t) => {
//Action 2.
return BehaviorTreeStatus.Failure;
})
.end()
.build();
```
Then, *Tick* the behavior tree on each *update* of your *loop*
```
public async update(deltaTime: number): Promise {
await this.tree.tick(new TimeData(deltaTime));
}
```
## Behavior Tree Status
Behavior tree nodes must return the following status codes:
* *BehaviorTreeStatus.Success*: The node has finished what it was doing and succeeded.
* *BehaviorTreeStatus.Failure*: The node has finished, but failed.
* *BehaviorTreeStatus.Running*: The node is still working on something.
## Node Types
### Action / Leaf-Node
Call the *do* function to create an action node at the leaves of the behavior tree.
```
.do("do-something", async (t) => {
// ... Do something ...
return BehaviorTreeStatus.Success;
});
```
The return value defines the status of the node. Return one of the statuses from above.
### Sequence
Runs each child node in sequence. Fails for the first child node that *fails*. Moves to the next child when the current running child *succeeds*. Stays on the current child node while it returns *running*. Succeeds when all child nodes have succeeded.
```
.sequence("my-sequence")
.do("action1", async (t) => { // Run this.
// Action 1.
return BehaviorTreeStatus.Success;
})
.do("action2", async (t) => { // Then run this.
//Action 2.
return BehaviorTreeStatus.Failure;
})
.end()
```
### Parallel
Runs all child nodes in parallel. Continues to run until a required number of child nodes have either *failed* or *succeeded*.
```
let numRequiredToFail: number = 2;
let numRequiredToSuccess: number = 2;
.parallel("my-parallel"m numRequiredtoFail, numRequiredToSucceed)
.do("action1", async (t) => { // Run this at the same time as action2
// Parallel action 1
return BehaviorTreeStatus.Running;
})
.do("action12, async (t) => { // Run this at the same time as action1
// Parallel action 2
return BehaviorTreeStatus.Running;
})
.end();
```
### Selector
Runs child nodes in sequence until it finds one that *succeeds*. Succeeds when it finds the first child that *succeeds*. For child nodes that *fail*, it moves forward to the next child node. While a child is *running* it stays on that child node without moving forward.
```
.selector("my-selector")
.do("action1", async (t) => {
// Action 1
return BehaviorTreeStatus.Failure; // Fail, move onto the next child
})
.do("action2", async (t) => {
// Action 2
return BehaviorTreeStatus.Success; // Success, stop here.
})
.do("action3", async (t) => {
// Action 3
return BehaviorTreeStatus.Success; // Doesn't get this far.
})
.end();
```
### Condition
The condition function is syntatic sugar for the *do* function. It allows the return of a boolean value that is then converted to *success* or *failure*. It is intended to be used with *Selector*.
```
.selector("my-selector")
.Condition("condition1", async (t) => this.someBooleanConditional()) // Predicate that returns *true* or *false*
.do("action1", async (t) => this.someAction()) // Action to run if the predicate evaluates to *true*
.end()
```
### Inverter
Inverts the *success* or *failure* of the child node. Continues running while the child node is *running*.
```
.inverter("inverter1")
.do("action1", async (t) => BehaviourTreeStatus.Success) // *Success* will be inverted to *failure*.
.end()
.inverter("inverter1")
.do("action1", async (t) => BehaviourTreeStatus.Failure) // *Failure* will be inverted to *success*.
.end()
```
## Nesting Behaviour Trees
Behaviour trees can be nested to any depth, for example:
```
.selector("parent")
.sequence("child-1")
...
.parallel("grand-child")
...
.end()
...
.end()
.sequence("child-2")
...
.end()
.end()
```
## Splicing a Sub-tree
Separately created sub-trees can be spliced into parent trees. This makes it easy to build behaviour trees from reusable components.
```
private createSubTree(): BehaviorTreeNodeInterface
{
return new BehaviourTreeBuilder()
.sequence("my-sub-tree")
.do("action1", async (t) => {
// Action 1.
return BehaviourTreeStatus.Success;
})
.Do("action2", async (t) => {
// Action 2.
return BehaviourTreeStatus.Success;
});
.end()
.build();
}
public startup(): void
{
this.tree = new BehaviourTreeBuilder()
.sequence("my-parent-sequence")
.Splice(this.createSubTree()) // Splice the child tree in.
.Splice(this.createSubTree()) // Splice again.
.end()
.build();
}
```