Documentation
¶
Overview ¶
Package bt is a composable behavior tree library for Go.
Import: "github.com/ratlabs-io/bt-go" (package name bt).
A behavior tree is a hierarchy of Behavior nodes. Each tick, a node returns one of Success, Failure, or Running. Leaf nodes (Action, Condition) do work; composites (Sequence, Selector, Parallel, …) combine children; decorators (Inverter, Repeater, Named, Observing, AbortHook, …) wrap a single child.
Environment (Env) ¶
Nodes receive an Env on every Tick. Env is not a context.Context:
- env.Context() — stdlib context for cancellation/deadlines only
- blackboard via Set/Get/GetAs — mutable agent/world state
Put agent data on the blackboard, never in context.WithValue.
Abort (Halt) ¶
When a parent abandons a Running child (preemption, branch switch, cancel), Halt is called on Haltable nodes so they can clean up (see AbortHook). Control-flow nodes that can abandon work (Sequence, Selector, memory composites, Parallel, BinarySelector, Switch, Conditional, decorators) implement Haltable and forward Halt to the abandoned child.
Observation ¶
NewObserving wraps a single node. Instrument / InstrumentRecorder wrap an entire tree so every tick reports to a callback or StatusRecorder.
Index ¶
- func GetAs[T any](env Env, key string) (T, bool)
- func GetKey[T any](env Env, key Key[T]) (T, bool)
- func Halt(env Env, node Behavior)
- func HaltAll(env Env, nodes ...Behavior)
- func InstrumentRecorder(root Behavior, rec *StatusRecorder) (Behavior, *StatusRecorder)
- func MustGet[T any](env Env, key string) T
- func MustGetKey[T any](env Env, key Key[T]) T
- func SetKey[T any](env Env, key Key[T], value T)
- type AbortHook
- type Action
- type BaseDecorator
- type Behavior
- type BinarySelector
- type Blackboard
- func (bb *Blackboard) AllEntries() []string
- func (bb *Blackboard) Clear()
- func (bb *Blackboard) Delete(key string)
- func (bb *Blackboard) Entries() []string
- func (bb *Blackboard) Get(key string) (interface{}, bool)
- func (bb *Blackboard) Has(key string) bool
- func (bb *Blackboard) HasLocal(key string) bool
- func (bb *Blackboard) Set(key string, value interface{})
- type ChildrenProvider
- type Composite
- type Condition
- type Conditional
- type Decorator
- type Env
- type EnvOption
- type Haltable
- type Inverter
- type Key
- type KeyFunc
- type MemorySelector
- type MemorySequence
- type Named
- type NodeVisualizer
- type Observing
- type Parallel
- type ParallelPolicy
- type Repeater
- type RunStatus
- type RunnerOption
- type Selector
- type Sequence
- type StatusRecorder
- type Switch
- type TickObserver
- type TreeRunner
- type TreeVisualizer
- type UntilFailure
- type UntilSuccess
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GetAs ¶
GetAs reads key from env's blackboard and type-asserts to T. ok is false if the key is missing or the value is not of type T.
Example ¶
package main
import (
"context"
"fmt"
"github.com/ratlabs-io/bt-go"
)
func main() {
env := bt.NewEnv(context.Background())
env.Set("health", 42)
h, ok := bt.GetAs[int](env, "health")
fmt.Println(h, ok)
}
Output: 42 true
func GetKey ¶ added in v1.6.0
GetKey reads key from env's blackboard and type-asserts to T. ok is false if the key is missing or the value is not of type T.
func InstrumentRecorder ¶ added in v1.6.0
func InstrumentRecorder(root Behavior, rec *StatusRecorder) (Behavior, *StatusRecorder)
InstrumentRecorder is like Instrument but records each node status into rec. If rec is nil, a new StatusRecorder is created. The recorder and instrumented root are both returned so callers can Visualize after ticking.
func MustGet ¶
MustGet is like GetAs but panics if the key is missing or has the wrong type. Prefer GetAs in production paths; MustGet is for tests and trusted setup.
func MustGetKey ¶ added in v1.6.0
MustGetKey is like GetKey but panics if the key is missing or has the wrong type.
func SetKey ¶ added in v1.6.0
SetKey stores value under key on env's blackboard.
Example ¶
package main
import (
"context"
"fmt"
"github.com/ratlabs-io/bt-go"
)
func main() {
const Health bt.Key[int] = "health"
env := bt.NewEnv(context.Background())
bt.SetKey(env, Health, 100)
fmt.Println(bt.MustGetKey(env, Health))
}
Output: 100
Types ¶
type AbortHook ¶
type AbortHook struct {
BaseDecorator
OnAbort func(env Env)
// contains filtered or unexported fields
}
AbortHook runs a callback when the node is Halted while still considered active (last tick returned Running). Use it for cleanup when a reactive parent preempts a long-running branch (stop pathing, clear target, etc.).
func NewAbortHook ¶
NewAbortHook wraps child with an abort callback.
Example ¶
package main
import (
"context"
"fmt"
"github.com/ratlabs-io/bt-go"
)
func main() {
env := bt.NewEnv(context.Background())
low := bt.NewAbortHook(
bt.NewAction(func(env bt.Env) bt.RunStatus { return bt.Running }),
func(env bt.Env) { fmt.Println("aborted") },
)
highReady := false
sel := bt.NewSelector(
bt.NewAction(func(env bt.Env) bt.RunStatus {
if highReady {
return bt.Success
}
return bt.Failure
}),
low,
)
fmt.Println(sel.Tick(env))
highReady = true
fmt.Println(sel.Tick(env))
}
Output: Running aborted Success
type Action ¶
type Action struct {
// contains filtered or unexported fields
}
Action is a leaf node that runs a user-supplied function.
type BaseDecorator ¶
type BaseDecorator struct {
Child Behavior
}
BaseDecorator holds the child pointer shared by concrete decorators.
func (*BaseDecorator) GetChild ¶
func (d *BaseDecorator) GetChild() Behavior
GetChild returns the decorated child.
func (*BaseDecorator) HaltChild ¶
func (d *BaseDecorator) HaltChild(env Env)
HaltChild aborts the child if it is Haltable. Embedded types may call this from Halt.
func (*BaseDecorator) SetChild ¶
func (d *BaseDecorator) SetChild(child Behavior)
SetChild sets the decorated child.
type Behavior ¶
type Behavior interface {
// Tick executes one step of the node and returns its status.
Tick(env Env) RunStatus
}
Behavior is implemented by every node in a behavior tree.
func Instrument ¶ added in v1.6.0
func Instrument(root Behavior, after TickObserver) Behavior
Instrument returns a new tree that reports every node tick to after.
The original tree is not modified. Structure is preserved: composites, decorators, BinarySelector, Switch, and Conditional are rebuilt with instrumented children, then each rebuilt node is wrapped in Observing.
after may be nil (structure is still cloned/wrapped). Pointer identity of nodes differs from root — use the returned tree for Tick and visualization.
This is the deep-observation alternative to wrapping individual leaves with NewObserving. Prefer per-node Observing when only a few nodes matter.
Example ¶
package main
import (
"context"
"fmt"
"github.com/ratlabs-io/bt-go"
)
func main() {
env := bt.NewEnv(context.Background())
root := bt.NewSequence(
bt.NewNamed("A", bt.NewAction(func(env bt.Env) bt.RunStatus { return bt.Success })),
)
var ticks int
tree := bt.Instrument(root, func(node bt.Behavior, status bt.RunStatus) {
ticks++
})
_ = tree.Tick(env)
fmt.Println(ticks >= 1)
}
Output: true
type BinarySelector ¶
type BinarySelector struct {
Condition Behavior
IfTrue Behavior
IfFalse Behavior
// contains filtered or unexported fields
}
BinarySelector chooses between two branches based on a condition behavior.
If Condition returns Success, IfTrue is ticked; otherwise IfFalse is ticked. Condition statuses other than Success (including Running) select IfFalse. For a boolean leaf, pass a *Condition.
When the selected branch changes while the previous branch was Running, the abandoned branch is Halted. Halt propagates to the last Running branch.
func NewBinarySelector ¶
func NewBinarySelector(condition, ifTrue, ifFalse Behavior) *BinarySelector
NewBinarySelector creates a BinarySelector.
func (*BinarySelector) Halt ¶ added in v1.6.0
func (node *BinarySelector) Halt(env Env)
Halt aborts the last running branch.
func (*BinarySelector) Tick ¶
func (node *BinarySelector) Tick(env Env) RunStatus
Tick evaluates Condition and runs the matching branch.
type Blackboard ¶
type Blackboard struct {
// contains filtered or unexported fields
}
Blackboard is a hierarchical, thread-safe key-value store for tree state.
Child blackboards can see parent entries (Get/Has walk upward). Writes and deletes apply only to the local blackboard, so a child can shadow a parent key without mutating it.
func NewBlackboard ¶
func NewBlackboard() *Blackboard
NewBlackboard creates an empty root blackboard.
func NewBlackboardWithParent ¶
func NewBlackboardWithParent(parent *Blackboard) *Blackboard
NewBlackboardWithParent creates a blackboard that falls back to parent on miss.
func (*Blackboard) AllEntries ¶
func (bb *Blackboard) AllEntries() []string
AllEntries returns keys visible from this blackboard, including parents. Local keys shadow parent keys of the same name (counted once).
func (*Blackboard) Clear ¶
func (bb *Blackboard) Clear()
Clear removes all local entries. Parents are unaffected.
func (*Blackboard) Delete ¶
func (bb *Blackboard) Delete(key string)
Delete removes a key from this blackboard only.
func (*Blackboard) Entries ¶
func (bb *Blackboard) Entries() []string
Entries returns keys set on this blackboard (not parents).
func (*Blackboard) Get ¶
func (bb *Blackboard) Get(key string) (interface{}, bool)
Get retrieves a value, checking this blackboard then parents.
func (*Blackboard) Has ¶
func (bb *Blackboard) Has(key string) bool
Has reports whether key exists on this blackboard or any parent.
func (*Blackboard) HasLocal ¶
func (bb *Blackboard) HasLocal(key string) bool
HasLocal reports whether key is set on this blackboard (ignoring parents).
func (*Blackboard) Set ¶
func (bb *Blackboard) Set(key string, value interface{})
Set stores a value on this blackboard only.
type ChildrenProvider ¶
type ChildrenProvider interface {
GetChildren() []Behavior
}
ChildrenProvider is implemented by nodes that expose multiple children. Used by tooling (visualization) without type-switching every composite.
type Composite ¶
type Composite struct {
Children []Behavior
}
Composite is embedded by multi-child control nodes. Children are public so callers and tools (e.g. visualizers) can inspect the tree.
func (*Composite) GetChildren ¶
GetChildren returns the composite's child nodes.
type Condition ¶
type Condition struct {
// contains filtered or unexported fields
}
Condition is a leaf that maps a boolean check to Success or Failure. It never returns Running.
func NewCondition ¶
NewCondition creates a Condition from checkFunc. If checkFunc is nil, Tick returns Failure.
type Conditional ¶
type Conditional struct {
Condition *Condition
Action Behavior
// contains filtered or unexported fields
}
Conditional runs Action only when Condition succeeds. If the condition fails, Conditional returns Failure without ticking Action. Condition must be non-nil; a nil Action is treated as Failure when selected.
When Condition fails after Action was Running, Action is Halted. Halt propagates to Action when it was left Running.
func NewConditional ¶
func NewConditional(condition *Condition, action Behavior) *Conditional
NewConditional creates a Conditional with the given condition and action.
func (*Conditional) Halt ¶ added in v1.6.0
func (c *Conditional) Halt(env Env)
Halt aborts Action if it was left Running.
func (*Conditional) Tick ¶
func (c *Conditional) Tick(env Env) RunStatus
Tick checks the condition, then optionally runs the action.
type Env ¶
type Env interface {
// Context returns the stdlib context used for cancellation and deadlines.
// It is never used as a value bag for agent state.
Context() context.Context
// Blackboard returns the hierarchical store for agent/world state.
Blackboard() *Blackboard
// Set stores a value on the blackboard (convenience for Blackboard().Set).
Set(key string, value interface{})
// Get reads a value from the blackboard hierarchy.
Get(key string) (value interface{}, ok bool)
// Delete removes a key from this blackboard only (not parents).
Delete(key string)
// Has reports whether key exists on this blackboard or any parent.
Has(key string) bool
}
Env is the per-tick environment passed to every node.
It is intentionally not a context.Context. The two concerns are separate:
- Context() — stdlib context.Context for cancellation and deadlines only
- Blackboard — mutable agent/world state (hierarchical key-value store)
Do not put agent state in context.WithValue. Use the blackboard (or the convenience Set/Get/Delete/Has methods, which write through to it).
Env does not implement context.Context (has-a, not is-a).
type EnvOption ¶
type EnvOption func(*env)
EnvOption configures an Env at construction time.
func WithBlackboard ¶
func WithBlackboard(bb *Blackboard) EnvOption
WithBlackboard sets the blackboard used by the env. If bb is nil, a fresh blackboard is used instead.
type Haltable ¶
type Haltable interface {
Halt(env Env)
}
Haltable is implemented by nodes that need cleanup when a parent aborts them without delivering a terminal Success/Failure tick (preemption, cancel).
Halt must be safe to call when the node is not running (no-op). Composites that track a running child should Halt that child and clear memory. Reset does not Halt — call Halt explicitly when aborting mid-run.
type Inverter ¶
type Inverter struct {
BaseDecorator
}
Inverter swaps Success ↔ Failure. Running is unchanged.
func NewInverter ¶
NewInverter creates an Inverter around child.
type Key ¶ added in v1.6.0
Key is a typed blackboard key. The type parameter documents the value type expected at that key; it is not enforced by the store itself.
const Health bt.Key[int] = "health" bt.SetKey(env, Health, 100) h, ok := bt.GetKey(env, Health)
String keys remain fully supported via Env.Set/Get and GetAs. Key helpers are an additive, compile-time documentation layer on the same blackboard.
type MemorySelector ¶
type MemorySelector struct {
Composite
// contains filtered or unexported fields
}
MemorySelector is a Selector that remembers which child was Running.
Unlike the reactive Selector (NewSelector), once a child returns Running the next Tick resumes at that child and does not re-evaluate higher-priority (earlier) siblings until the remembered child finishes.
If the remembered child fails, evaluation continues with later siblings only (earlier ones are not re-tried until the whole selector returns Failure and memory is cleared). Call Reset to clear memory without ticking; Halt aborts.
func NewMemorySelector ¶
func NewMemorySelector(children ...Behavior) *MemorySelector
NewMemorySelector creates a memory Selector with the given children.
func (*MemorySelector) Halt ¶
func (s *MemorySelector) Halt(env Env)
Halt aborts the remembered child (if any) and clears memory.
func (*MemorySelector) Reset ¶
func (s *MemorySelector) Reset()
Reset clears resume state so the next Tick starts at the first child. It does not Halt the current child; call Halt when aborting mid-run.
func (*MemorySelector) RunningIndex ¶
func (s *MemorySelector) RunningIndex() int
RunningIndex returns the remembered child index, or -1 when idle.
func (*MemorySelector) Tick ¶
func (s *MemorySelector) Tick(env Env) RunStatus
Tick tries children from the remembered index. See type docs.
type MemorySequence ¶
type MemorySequence struct {
Composite
// contains filtered or unexported fields
}
MemorySequence is a Sequence that remembers which child was Running.
Unlike the reactive Sequence (NewSequence), once a child returns Running the next Tick resumes at that child and does not re-tick earlier siblings that already succeeded in this run.
Memory is cleared when the sequence returns Success or Failure (including nil-child failure). Call Reset to clear memory without ticking; Halt aborts the current child and resets. Idle runningIndex is -1 (Halt is a no-op).
func NewMemorySequence ¶
func NewMemorySequence(children ...Behavior) *MemorySequence
NewMemorySequence creates a memory Sequence with the given children.
Example ¶
package main
import (
"context"
"fmt"
"github.com/ratlabs-io/bt-go"
)
func main() {
env := bt.NewEnv(context.Background())
n := 0
tree := bt.NewMemorySequence(
bt.NewAction(func(env bt.Env) bt.RunStatus {
fmt.Println("prep")
return bt.Success
}),
bt.NewAction(func(env bt.Env) bt.RunStatus {
n++
fmt.Println("work", n)
if n < 2 {
return bt.Running
}
return bt.Success
}),
)
fmt.Println(tree.Tick(env))
fmt.Println(tree.Tick(env))
}
Output: prep work 1 Running work 2 Success
func (*MemorySequence) Halt ¶
func (s *MemorySequence) Halt(env Env)
Halt aborts the child at the resume index (if any) and resets memory.
func (*MemorySequence) Reset ¶
func (s *MemorySequence) Reset()
Reset clears resume state so the next Tick starts at the first child. It does not Halt the current child; call Halt when aborting mid-run.
func (*MemorySequence) RunningIndex ¶
func (s *MemorySequence) RunningIndex() int
RunningIndex returns the child index that will be resumed on the next Tick, or -1 when idle / after a terminal status.
func (*MemorySequence) Tick ¶
func (s *MemorySequence) Tick(env Env) RunStatus
Tick executes children from the remembered index. See type docs.
type Named ¶
type Named struct {
BaseDecorator
Name string
}
Named wraps a child with a human-readable label for visualization and logs. Tick is a pure pass-through.
func (*Named) VisualizeNode ¶
VisualizeNode returns the custom name for TreeVisualizer.
type NodeVisualizer ¶
type NodeVisualizer interface {
VisualizeNode() string
}
NodeVisualizer lets custom nodes supply their own label for tree dumps.
type Observing ¶
type Observing struct {
BaseDecorator
// AfterTick is invoked after the child is ticked (including when child is nil → Failure).
AfterTick TickObserver
}
Observing wraps a child and reports each tick result to AfterTick. Only this node is observed — wrap additional nodes to observe deeper, or use Instrument / InstrumentRecorder for the whole tree.
func NewObserving ¶
func NewObserving(child Behavior, after TickObserver) *Observing
NewObserving creates an Observing decorator. after may be nil (no-op).
type Parallel ¶
type Parallel struct {
Composite
// contains filtered or unexported fields
}
Parallel ticks all children each call and aggregates results by policy.
By default ticks are sequential (deterministic order, same stack) — the usual behavior-tree meaning of “parallel”: all children get a chance this frame. Use NewConcurrentParallel for one goroutine per child.
Children share the same Env. Under concurrent mode the blackboard is thread-safe; other shared mutable state in actions must be synchronized.
Every child is ticked on every Parallel.Tick (no sticky completion memory). When the policy returns Success or Failure while some children are still Running, those residual Running children are Halted for this tick.
func NewConcurrentParallel ¶
func NewConcurrentParallel(policy ParallelPolicy, children ...Behavior) *Parallel
NewConcurrentParallel creates a Parallel that ticks each child in its own goroutine.
func NewParallel ¶
func NewParallel(policy ParallelPolicy, children ...Behavior) *Parallel
NewParallel creates a sequential Parallel node (classic BT parallel).
Example ¶
package main
import (
"context"
"fmt"
"github.com/ratlabs-io/bt-go"
)
func main() {
env := bt.NewEnv(context.Background())
p := bt.NewParallel(bt.RequireAll,
bt.NewAction(func(env bt.Env) bt.RunStatus {
fmt.Println("a")
return bt.Success
}),
bt.NewAction(func(env bt.Env) bt.RunStatus {
fmt.Println("b")
return bt.Success
}),
)
fmt.Println(p.Tick(env))
}
Output: a b Success
func (*Parallel) Concurrent ¶
Concurrent reports whether children are ticked in goroutines.
func (*Parallel) Policy ¶
func (p *Parallel) Policy() ParallelPolicy
Policy returns the aggregation policy.
type ParallelPolicy ¶
type ParallelPolicy int
ParallelPolicy defines how a Parallel node aggregates child results.
const ( // RequireOne succeeds if at least one child succeeds; fails only if all fail. RequireOne ParallelPolicy = iota // RequireAll succeeds only if all children succeed; fails if any fail. RequireAll // SuccessOnAll succeeds only if all children succeed; otherwise Running // (never Failure — failures are treated as “not yet success”). SuccessOnAll // SuccessOnOne succeeds if at least one child succeeds; otherwise Running // (never Failure). SuccessOnOne )
func (ParallelPolicy) String ¶
func (p ParallelPolicy) String() string
String returns the policy name.
type Repeater ¶
type Repeater struct {
BaseDecorator
Count int
// contains filtered or unexported fields
}
Repeater runs its child a fixed number of successful times. Each Tick advances at most one successful child completion. Failure from the child aborts and resets the counter. count <= 0 means infinite (always returns Running after a successful child tick).
func NewRepeater ¶
NewRepeater creates a Repeater. count <= 0 means repeat forever.
type RunnerOption ¶
type RunnerOption func(*TreeRunner)
RunnerOption configures a TreeRunner.
func WithCallbacks ¶
func WithCallbacks(onSuccess, onFailure, onRunning func()) RunnerOption
WithCallbacks registers hooks invoked after each tick for the returned status. Nil callbacks are treated as no-ops.
func WithTickRate ¶
func WithTickRate(rate time.Duration) RunnerOption
WithTickRate sets how often the tree is ticked. Default is 100ms (10 Hz).
type Selector ¶
type Selector struct {
Composite
// contains filtered or unexported fields
}
Selector ticks children left-to-right until one succeeds or is still running.
Semantics (reactive / restart-from-start each tick — classic priority order):
- Success from any child → Success
- Running from any child → Running
- All Failure → Failure
Earlier children have higher priority: every Tick re-evaluates from the first child, so a higher-priority branch can preempt a lower one that was Running. When preemption occurs, the abandoned child is Halted if it implements Haltable. For stick-to-running-child semantics (no preemption), use NewMemorySelector.
func NewSelector ¶
NewSelector creates a Selector with the given children, in priority order.
type Sequence ¶
type Sequence struct {
Composite
// contains filtered or unexported fields
}
Sequence ticks children left-to-right until one fails or is still running.
Semantics (reactive / restart-from-start each tick):
- Failure from any child → Failure
- Running from any child → Running
- All Success → Success
Sequence does not remember progress for control flow; each Tick starts at the first child. It does track the last Running child so that if an earlier sibling later fails (or the sequence is Halted), the abandoned child receives Halt. Children that already returned a terminal status this tick are not Halted. For resume-from-running control flow, use NewMemorySequence.
func NewSequence ¶
NewSequence creates a Sequence with the given children, in order.
Example ¶
package main
import (
"context"
"fmt"
"github.com/ratlabs-io/bt-go"
)
func main() {
env := bt.NewEnv(context.Background())
tree := bt.NewSequence(
bt.NewAction(func(env bt.Env) bt.RunStatus {
fmt.Println("step1")
return bt.Success
}),
bt.NewAction(func(env bt.Env) bt.RunStatus {
fmt.Println("step2")
return bt.Success
}),
)
fmt.Println(tree.Tick(env))
}
Output: step1 step2 Success
type StatusRecorder ¶
type StatusRecorder struct {
// contains filtered or unexported fields
}
StatusRecorder records the status of nodes as they are ticked. It is a debugging aid, not a tree node itself.
Prefer wrapping ticks you care about:
rec := bt.NewStatusRecorder() status := rec.Tick(env, root) // records root only
For full-tree status maps, use InstrumentRecorder (or wrap leaves with Observing).
func NewSaveTreeSnapshot
deprecated
func NewSaveTreeSnapshot() *StatusRecorder
NewSaveTreeSnapshot is a deprecated alias for NewStatusRecorder.
Deprecated: use NewStatusRecorder.
func NewStatusRecorder ¶
func NewStatusRecorder() *StatusRecorder
NewStatusRecorder creates an empty status recorder.
func (*StatusRecorder) GetStatusMap ¶
func (s *StatusRecorder) GetStatusMap() map[Behavior]RunStatus
GetStatusMap returns the map of recorded node statuses.
func (*StatusRecorder) Tick ¶
func (s *StatusRecorder) Tick(env Env, node Behavior) RunStatus
Tick runs node, records its status, and returns that status. Only the node itself is recorded — not its descendants.
func (*StatusRecorder) Visualize ¶
func (s *StatusRecorder) Visualize(root Behavior) string
Visualize renders root with recorded statuses annotated.
type Switch ¶
type Switch struct {
KeyFunc KeyFunc
Cases map[string]Behavior
Default Behavior
// contains filtered or unexported fields
}
Switch selects a child by a dynamic string key.
KeyFunc is evaluated every Tick. If Cases[key] exists it is ticked; otherwise Default is ticked. If neither matches, Switch returns Failure.
When the selected case changes while the previous case was Running, the abandoned case is Halted. Halt propagates to the last Running case.
type TickObserver ¶
TickObserver is called after a watched node finishes a Tick.
type TreeRunner ¶
type TreeRunner struct {
// contains filtered or unexported fields
}
TreeRunner ticks a behavior tree on a fixed interval until cancelled.
func NewTreeRunner ¶
func NewTreeRunner(tree Behavior, options ...RunnerOption) *TreeRunner
NewTreeRunner returns a runner for tree with optional configuration.
func (*TreeRunner) Run ¶
func (tr *TreeRunner) Run(env Env)
Run ticks the tree at the configured rate until env.Context() is cancelled.
Cancellation stops scheduling further ticks and Halts the tree so Haltable nodes can clean up. A Tick that is already in progress is not interrupted — long-running actions should watch env.Context().Done() themselves.
func (*TreeRunner) RunOnce ¶
func (tr *TreeRunner) RunOnce(env Env) RunStatus
RunOnce ticks the tree once, fires the matching callback, and returns the status. It does not Halt afterward (the tree may still be Running).
type TreeVisualizer ¶
type TreeVisualizer struct {
// contains filtered or unexported fields
}
TreeVisualizer renders a behavior tree as indented text.
func NewTreeVisualizer ¶
func NewTreeVisualizer(root Behavior) *TreeVisualizer
NewTreeVisualizer creates a visualizer for root.
func (*TreeVisualizer) Visualize ¶
func (tv *TreeVisualizer) Visualize() string
Visualize returns a multi-line text representation of the tree.
func (*TreeVisualizer) WithNodeStatuses ¶
func (tv *TreeVisualizer) WithNodeStatuses(statuses map[Behavior]RunStatus) *TreeVisualizer
WithNodeStatuses enables status annotations from the given map.
type UntilFailure ¶
type UntilFailure struct {
BaseDecorator
}
UntilFailure ticks the child until it returns Failure. When the child fails, the decorator returns Success (the wait succeeded).
func NewUntilFailure ¶
func NewUntilFailure(child Behavior) *UntilFailure
NewUntilFailure creates an UntilFailure decorator.
func (*UntilFailure) Tick ¶
func (u *UntilFailure) Tick(env Env) RunStatus
Tick returns Success when the child fails; otherwise Running.
type UntilSuccess ¶
type UntilSuccess struct {
BaseDecorator
}
UntilSuccess ticks the child until it returns Success. Failure and Running both yield Running from the decorator.
func NewUntilSuccess ¶
func NewUntilSuccess(child Behavior) *UntilSuccess
NewUntilSuccess creates an UntilSuccess decorator.
func (*UntilSuccess) Tick ¶
func (u *UntilSuccess) Tick(env Env) RunStatus
Tick returns Success only when the child succeeds; otherwise Running.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
agent
command
Agent demonstrates reactive vs memory control flow for a simple NPC.
|
Agent demonstrates reactive vs memory control flow for a simple NPC. |
|
hello
command
Hello is a minimal bt-go example: a two-step Sequence that prints a greeting.
|
Hello is a minimal bt-go example: a two-step Sequence that prints a greeting. |