Skip to content

Core Concepts

Control the execution flow of child nodes.

Executes children in order. Fails if any child fails.

.sequence('AttackSequence')
.condition('hasTarget') // If false, sequence fails
.action('moveToTarget') // If fails, sequence fails
.action('attack') // If succeeds, sequence succeeds
.end()

Tries children until one succeeds. Fails if all children fail.

.selector('FindTarget')
.action('findNearestEnemy') // Try first
.action('findNearestItem') // Try if first fails
.action('wander') // Fallback
.end()

Executes all children simultaneously.

.parallel('CombatActions', {
successPolicy: 'all', // 'all' | 'any'
failurePolicy: 'any' // 'all' | 'any'
})
.action('playAttackAnimation')
.action('dealDamage')
.action('playSound')
.end()

Performs a specific task.

.action('attack', { damage: 10 })

Checks a condition without side effects.

.condition('isHealthLow', { threshold: 30 })

Modify child behavior.

// Invert result
.inverter()
.condition('isEnemy')
.end()
// Repeat until failure
.repeatUntilFail()
.action('patrol')
.end()
// Timeout
.timeout(5000)
.action('searchForTarget')
.end()

Every node returns one of these statuses:

StatusDescription
SuccessTask completed successfully
FailureTask failed
RunningTask still in progress
import { TaskStatus } from '@esengine/behavior-tree';
class MyAction implements INodeExecutor {
execute(context: NodeExecutionContext): TaskStatus {
if (/* completed */) return TaskStatus.Success;
if (/* failed */) return TaskStatus.Failure;
return TaskStatus.Running; // Still working
}
}
// Local blackboard - per behavior tree instance
runtime.setBlackboardValue('localVar', value);
// Global blackboard - shared across all trees
runtime.setGlobalBlackboardValue('globalVar', value);
class PatrolAction implements INodeExecutor {
execute(context: NodeExecutionContext): TaskStatus {
// Read from blackboard
const target = context.runtime.getBlackboardValue('patrolTarget');
const speed = context.runtime.getBlackboardValue('moveSpeed');
// Write to blackboard
context.runtime.setBlackboardValue('lastPosition', currentPos);
return TaskStatus.Success;
}
}
interface NodeExecutionContext {
readonly node: IBehaviorTreeNode; // Current node data
readonly runtime: BehaviorTreeRuntimeComponent; // Runtime state
readonly entity: Entity; // Owner entity
readonly scene: Scene; // Current scene
readonly deltaTime: number; // Frame delta time
}
BehaviorTreeData (Pure Data)
├── Serializable JSON structure
├── Node definitions
└── Blackboard schema
BehaviorTreeRuntimeComponent (State)
├── Current execution state
├── Blackboard values
└── Node status cache
BehaviorTreeExecutionSystem (Logic)
├── Drives tree execution
├── Manages node traversal
└── Calls INodeExecutor.execute()
INodeExecutor (Behavior)
├── Stateless design
├── Receives context
└── Returns TaskStatus