In the Behave runtime, a tree is the runtime representation of a tree you designed and an agent is one of your own classes, a player- / animation- / squad- controller or whatever you like, either implementing the Behave IAgent interface or deriving from a generated agent blueprint.
All that is required of an agent derived from the IAgent interface is that it implements a few default handlers. Aside from those, direct action (leaf node) handlers are optional. Blueprint derived agents are not required to override anything as all handlers are already implemented with default virtual implementations.
Default action handlers as found by introspection on IAgent classes:
In Behave 1, decorators were more similar to actions in that their behaviour was dictated directly by the agent class through decorator handlers. Since in Behave 2, decorators are now control nodes, there is no need for on-agent decorator handlers. Behaviour is strictly dictated via the control connection. More information in the Nodes section.
When instantiating a tree, an agent reference must be given, as this agent will be the default recipient of callbacks from the tree instance. For agents implementing the agent interface, trees will on instantiation dynamically hook up handlers using introspection.
The alternative agent blueprints are set up in the Behave designer as a name and a list of supported trees. They are generated into abstract classes with virtual handlers for the actions used by the supported trees.
Though agent blueprints are limited in that their advantages only hold true in the case of the trees they have been designed to handle, they do save you the introspection overhead on tree instantiation. Additionally, given that their virtual handlers are known at compile time, you get code completion when overriding these.
Minimal agent-tree setup, Unity example, library named “MyLibrary” containing a tree named “MyTree”:
The coroutine loop ticking the tree in Start is not strictly required, but it is a very common pattern which you will very likely find yourself repeating in many implementations.
Similarly, note how the Frequency property of the tree does not automatically have influence on the ticking of the tree. It is merely a variable which the designer can set when configuring the tree, which the programmer may then choose to use as makes most sense.
From a library named “MyLibrary”, the following runtime class is compiled:
Trees do not update themselves, but in stead need to be ticked. Ticking a tree will result in it in-turn ticking its currently active node. This node could be a control node, each of which have certain rules which dictate how they handle their child node(s), or it could be an action.
Actions are logic constructs which are expected to perform a task and / or query a state and return success / failure / running. As these are highly context specific, they need to be handled by the agent associated with their tree.
Each tree tick will therefore always result in at least one action tick. To your code, that means calling the tick method on a tree results in one or more action handlers or the default handlers being invoked by that tree.
In addition to direct handlers and default handlers, a tree can have a forward set for any of its actions. The result being that for the given action on the given tree instance, the forwarded handler will be used in stead direct or default handlers.
A node, and therefore also an action, goes through three phases:
The first time a node is ticked since last reset, it enters its init phase just before its first tick phase. In the case of actions being handled, this means a separate action handler for the init call. Actions with no init handlers will assume successful init.
Init is useful for setting up state such as counters or resource locks. If the result of a node tick is running, the behaviour tree will not progress to the next target node on its next tick, but will in stead re-tick the same node.
This can result in only one entry to the init phase, followed by multiple ticks. Once a node returns success or failure, it is reset – which in the case of actions results in an invocation of the action reset handler or the default reset handler.
Nodes can also get reset if their subtree is reset directly or by an interrupter.
Though building a library in debug mode will ensure generation and updating of debug information at runtime, you still need to pass this information to monitoring connections at a set rate.
This can either be done by directly calling
Behave.Debugger.Debugging.Update (); at some frequency or calling
Behave.Debugger.DebugUpdater.Start (int frequency = 0); once you want to start sending updates.