This page provides instructions for creating and implementing custom behavior tree nodes; as explained in the following section, these nodes can be of three types namely, Action, Composites or Decorators.
The Base Class
Action nodes represent the leaf nodes in a Behavior Tree and are responsible for causing an AI agent to perform a specific action such as moving between locations, speaking dialog or playing animations.
Composite nodes have multiple children that are executed as per a specific policy/strategy.
A Decorator node has only a single child, to which it adds extra functionality regardless of what the child node does.
All nodes, regardless of their type, must have a few basic functions defined in order to work properly; these are described below.
As described on the previous page, Behavior Trees maintain both Configuration and Runtime Data.
- Configuration Data is stored as member data of the node's class.
- Runtime Data is stored in the RuntimeData struct. Every node must have a RuntimeData struct defined regardless of whether it is used or not; the struct can hence even be left empty. If not empty, the struct:
- Must be initialized in the OnInitialize function of the node.
- Should be cleared in the OnTerminate function of the node.
- Should be updated in the Update function of the node.
- Can be accessed by calling the GetRuntimeData(context) function.
The following functions are executed in different circumstances while a Behavior Tree node is active.
All nodes also require a HandleEvent function.
Actions and Decorators have a default implementation for this function; this is because Action nodes don't have children, while Decorators only have one, making implementations trivial in this case.
Composite nodes, however, may have multiple children that can be active in different situations, and hence require a specific implementation for the HandleEvent function. These Composite nodes need to know how to handle a event and how to propagate it to the children.
Since Behavior Trees on CRYENGINE are described in XML, specific functions need to be implemented in order to load and store them from disk.
For example, this is what a simplified form of the LoadFromXml function of the SendEvent action node looks like. Since LoadFromXml is executed when the Behavior Tree is loaded from a file, this function is mandatory.
Find more information on reading and writing XML with CRYNENGINE here.
Errors in the Saving/Loading of XML files can be reported by using the Error reporter, and by calling BehaviorTree: ErrorReporter for pre-defined error messages.
These messages can be used as follows:
Here is a simplified form of the CreateXmlDescription function for the same node. As opposed to the LoadFromXml function, CreateXmlDescriptionis optional; it is required only when we want to use a node in the Behavior Tree Editor.
CreateXmlDescription is executed when the Tree is saved and written to a file.
Behavior Tree nodes use the Yasli library for serialization, so they require a Serialize function to be implemented. Serializing of nodes works in the same way as it does in other modules.
More information on CRYENGINE's Serialization Library can be found here.
Data Through Context
It is sometimes necessary to have access to Behavior Tree data when serializing a node. This can be achieved through the archive.context property of the Archive.
Errors in the Serialization process can be reported by calling archive.error and using pre-defined errors messages in SerializationUtils:Messages.
These messages can be used as follows:
The GetCustomDebugText function has an output string that stores what is to be displayed on screen while debugging a Behavior Tree. For example, the following piece of code belongs to the SendTransitionSignal Action node.
Real-time debugging is enabled via the Behavior Tree Editor's Debug Menu.
In-game, the above code will create the following debug text where the SendTransitionSignal node displays the value of m_signalName, which is GoTo_Combat.
When the debugText ="Smile! I am taking a picture" line is used in the above code, the SendTransitionSignal node displays the custom debug text as shown.
debugText=Smile! I am taking a picture
Use Debug Log
Messages can be written to the Behavior Tree log by accessing the UpdateContext parameter, from any of the core execution functions (OnInitialize, Update and OnTerminate) described in the Custom Nodes documentation. This will appear as folows:
The above code writes the Hello World message to the Debug Log every time the node executes the Update function. During the execution of your game, this message will be displayed on screen as shown below if the Debug → Show Log option has been enabled from the Behavior Tree Editor main menu.
Created nodes need to be registered before they can be used in a Behavior Tree.
This is done via the REGISTER_BEHAVIOR_TREE_NODE_WITH_SERIALIZATION(1, 2, 3, 4) macro where:
- 1 corresponds to the Behavior Tree manager (accessed through gEnv or gAIEnv);
- 2 corresponds to the class of the new node that needs to be added;
- 3 refers to the path of the node in the menu;
- 4 corresponds to the color of the node.
It is recommended to create a function to register all custom nodes as follows:
Table of Contents
- No labels