behavey
v0.1.0
Published
A behavior tree framework for JavaScript & TypeScript
Downloads
1
Readme
behavey
==========
A behavior tree framework for JavaScript & TypeScript (BETA)
To Install
npm add behavey
# or
yarn add behavey
How It Works
behavey consists of several pieces:
LambdaArgs
: a common and extensible data structure used by behavey to help manage and control behavior.Operation
: a common function that utilizsLambdaArgs
to execute behavioral patterns.Tree
: a common interface to hostOperation
constructs, bothsubroutine
andcoroutine
based.Mode
: a way to manage multipleTree
constructs to support shared (MinorMode
) and situational behaviors (MajorMode
).Executor
: a mechanism to manage multipleMode
s, switch between them, as well as capture events and manageLambdaArgs
.EventDispatcher
: a simple and powerful call-based method of registering and dispatching events.
Together you can use them to construct and execute a behavior tree:
const exec = create_executor_builder<MyMetaData>()
.add_major_mode(seek_threat)
.add_major_mode(attack_threat)
.create_major_mode(major =>
major
.set_name('idle-roam')
.create_tree(tree =>
tree
.set_root(
sel(
seq(
threat_detected,
play_alert_bark,
emt('bark-alert'),
tsn('seek-threat'),
),
seq(have_path, follow_path, set_walk),
seq(choose_random_location, determine_path, brk()),
idf(
choose_random_idle_pose,
set_stand_idle_1,
set_stand_idle_2,
set_stand_idle_3,
),
),
)
.build(),
)
.create_minor_mode(minor =>
minor
.set_name('alertable')
.add_event('bark-alert')
.add_event('explosion-alert')
.add_event('alarm-alert')
.set_tree(respond_to_alerts)
.build(),
)
.add_minor_mode(play_animation_track)
.build(),
)
.set_default_mode('idle-roam')
.build();
// execute the behavior passing your meta data
exec.behave(myData);
Operations
behavey provides a number of Operations
that represent logical constructs, such as:
smf
- run a function and store the returned result in a location in memory.chk
- check if a location in memory has a specific value.inv
- invert anOperation
so that its result is flipped: i.e.,true
becomesfalse
and vice-versa.seq
- run a sequence ofOperations
, only returningtrue
if all operations were successful.sel
- run a sequence ofOperations
, returningtrue
when the first succeeds.idf
- run a function that returns anumber
that is used to index into an array ofOperations
.lpv
- run anOperation
in a loop for as long as a memory location istrue
.
There are also concurrent
variations of Operations
that will evuate over several calls
import { coroutine, CResult, fnb_c, fnc, fnr_c, make_args, seq_c } from 'behavey';
const args = make_args();
// seq_c takes several `LambdaGenrators` and evaluates them over the course of several calls
const root = seq_c(
// `fnb_c` takes a `BooleanLambda` and turns it into a `LambdaGenerator`
fnb_c(()=> true),
// `fnr_c` takes a `ResultLambda` and turns it into a `LambdaGenerator`
fnr_c(()=> CResult.SUCCESS),
fnb_c(()=> true),
);
// `coroutine` takes a `LambdaGenerator` and turns it into a `Coroutine`
// it can then be successively called to progress the evaluation.
const cor = coroutine(root);
cor(args); // 1st `fnb_c` evaluated, returns `CResult.RUNNING`
cor(args); // 1st `fnr_c` evaluated, returns `CResult.RUNNING`
cor(args); // 2nd `fnb_c` evaluated, returns `CResult.RUNNING`
cor(args); // `seq_c` evaluated, returns `CResult.SUCCESS`
// coroutines can also be wrapped in a `fnc` to make them behave as if they were a `BooleanLambda`
const root = fnc(
seq_c(
// `fnb_c` takes a `BooleanLambda` and turns it into a `LambdaGenerator`
fnb_c(() => true),
// `fnr_c` takes a `ResultLambda` and turns it into a `LambdaGenerator`
fnr_c(() => CResult.SUCCESS),
fnb_c(() => true),
),
2, // max iterations per call
4, // how many iterations must ocurr before the coroutine is reset
false, // how `CResult.RUNNING` should be interpreted
);
root(args); // two iterations, returns `false`
root(args); // two iterations, returns `true`
root(args); // coroutine was reset, two iterations, returns `false`
root(args); // two iterations, returns `true`