Documentation ¶
Overview ¶
Package behaviortree provides a simple and powerful Go implementation of behavior trees without fluff.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Manager ¶
type Manager interface { Ticker // Add will register a new ticker under this manager Add(ticker Ticker) error }
Manager models an aggregate Ticker, which should stop gracefully on the first failure
func NewManager ¶
func NewManager() Manager
NewManager will construct an implementation of the Manager interface, which is a stateful set of Ticker implementations, aggregating the behavior such that the Done channel will close when ALL tickers registered with Add are done, Err will return a combined error if there are any, and Stop will stop all registered tickers.
Note that any error (of any registered tickers) will also trigger stopping, and stopping will prevent further Add calls from succeeding.
type Node ¶
Node represents an node in a tree, that can be ticked
func New ¶
New constructs a new behavior tree aliasing NewNode with vararg support for less indentation
type Status ¶
type Status int
Status is a type with three valid values, Running, Success, and Failure, the three possible states for BTs
func Selector ¶
Selector is a tick implementation that will succeed if no children fail, returning running if any children return running, propagating any error
func Sequence ¶
Sequence is a tick implementation that will succeed if any children succeed, returning running if any children return running, propagating any error
type Ticker ¶
type Ticker interface { // Done will close when the ticker is fully stopped. Done() <-chan struct{} // Err will return any error that occurs. Err() error // Stop shutdown the ticker asynchronously. Stop() }
Ticker models a node runner
func NewTicker ¶
NewTicker constructs a new Ticker, which simply uses time.Ticker to tick the provided node periodically, note that a panic will occur if ctx is nil, duration is <= 0, or node is nil.
The node will tick until the first error or Ticker.Stop is called, or context is canceled, after which any error will be made available via Ticker.Err, before closure of the done channel, indicating that all resources have been freed, and any error is available.
func NewTickerStopOnFailure ¶
NewTickerStopOnFailure returns a new Ticker that will exit on the first Failure, but won't return a non-nil Err UNLESS there was an actual error returned, it's built on top of the same core implementation provided by NewTicker, and uses that function directly, note that it will panic if the node is nil, the panic cases for NewTicker also apply.
Example (Counter) ¶
ExampleNewTickerStopOnFailure_counter demonstrates the use of NewTickerStopOnFailure to implement more complex "run to completion" behavior using the simple modular building blocks provided by this package
var ( // counter is the shared state used by this example counter = 0 // printCounter returns a node that will print the counter prefixed with the given name then succeed printCounter = func(name string) Node { return New( func(children []Node) (Status, error) { fmt.Printf("%s: %d\n", name, counter) return Success, nil }, ) } // incrementCounter is a node that will increment counter then succeed incrementCounter = New( func(children []Node) (Status, error) { counter++ return Success, nil }, ) // ticker is what actually runs this example and will tick the behavior tree defined by a given node at a given // rate and will stop after the first failed tick or error or context cancel ticker = NewTickerStopOnFailure( context.Background(), time.Millisecond, New( Selector, // runs each child sequentially until one succeeds (success) or all fail (failure) New( Sequence, // runs each child in order until one fails (failure) or they all succeed (success) New( func(children []Node) (Status, error) { // succeeds while counter is less than 10 if counter < 10 { return Success, nil } return Failure, nil }, ), incrementCounter, printCounter("< 10"), ), New( Sequence, New( func(children []Node) (Status, error) { // succeeds while counter is less than 20 if counter < 20 { return Success, nil } return Failure, nil }, ), incrementCounter, printCounter("< 20"), ), ), // if both children failed (counter is >= 20) the root node will also fail ) ) // waits until ticker stops, which will be on the first failure of it's root node <-ticker.Done() // every Tick may return an error which would automatically cause a failure and propagation of the error if err := ticker.Err(); err != nil { panic(err) }
Output: < 10: 1 < 10: 2 < 10: 3 < 10: 4 < 10: 5 < 10: 6 < 10: 7 < 10: 8 < 10: 9 < 10: 10 < 20: 11 < 20: 12 < 20: 13 < 20: 14 < 20: 15 < 20: 16 < 20: 17 < 20: 18 < 20: 19 < 20: 20