MonoBehaviourTree
Simple event driven Behaviour tree for Unity projects
Install / Use
/learn @Qriva/MonoBehaviourTreeREADME
MonoBehaviourTree — Simple behaviour tree for Unity
<p align="center"> <img src="readme-image.png" alt="Screenshot"/> </p> This project is simple event driven behaviour tree based on Unity engine component system. This asset comes with minimal node library and tree visual editor.Important: This is not fully fledged visual scripting tool. Package has its own visual editor, however requires you to implement your own nodes.
Contribute
Contribution in any form is very welcome. Bugs, feature requests or feedback can be reported in form of Issues.
Getting started
The latest version can be installed via package manager using following git URL:<br> https://github.com/Qriva/MonoBehaviourTree.git#upm
<br>Alternatively you can copy the Assets/MonoBehaviourTree folder to your project or download from Unity Asset Store.
Examples of usage are available in package manager or in folder Samples containing demo scenes. If you copy assets manually you might want to delete Samples directory to get rid of redundant files.
This documentation assumes you have basic knowledge about behaviour trees. If you don't have it, you should check some online resources like this Game Developer article or Unreal Engine documentation.
Event Driven Behaviour Tree Overview
Standard behaviour tree design assumes three types of nodes: composites, decorators and leafs. Composites are used to define the flow in the tree, decorators can modify node results and leafs perform tasks or check conditions. This design has one major flaw - tree must be traversed from the beginning every single tick, otherwise it will not be possible to react to changes in state or data. Event driven tree is the fix to that problem. When tree gets update it continues from the last executed running node. Normally it would mean, that executed higher priority nodes will not be reevaluated immediately, but event driven BT introduces abort system to give possibility to reset tree to previous state, when certain event occur. Implementation used in this project is very similar to the one used in Unreal engine - leaf nodes are not used as conditions, instead they are in form of decorators. Additionally it is possible to create Service nodes which can perform task periodically.
Node Abort
When the tree is updated, the first evaluated thing are aborting nodes. If there is any aborting node, the tree will be reset to that position and execution will be continued from this node. In case there are multiple aborting nodes, the one closest to root will be selected. There are four abort types:
- None - don't do anything when change occurs
- Self - abort children running below
- Lower Priority - abort running nodes with lower priority (nodes to the right)
- Both - abort self and lower priority nodes
Execution order (priority) of nodes with common ancestor is defined by position on X axis, nodes to the left has higher priority.
Aborts can be performed only by Decorator nodes. See example abort implementation in Decorator section.
Basic Usage
The main core of behaviour tree is MonoBehaviourTree component. It contains most of tree state during runtime. It is important to note, that tree does not run automatically and must be updated by other script. This design gives you possibility to tick the tree in Update, FixedUpdate or custom interval. However, most of the time Update event will be used, so you can use component MBT Executor to do that.
In most of cases you will need some place to store shared data for nodes. You could implement your own component to do that, but instead it's better to use built in Blackboard component. Blackboard allows you to create observable variables of predefined types that are compatible with default nodes.
Node editor
To open tree editor window click "Open editor" button of MonoBehaviourTree component or click Unity menu: Window / Mono Behaviour Tree. In visual editor you can create, connect, delete and setup nodes.
Every behaviour tree needs an entry point called Root. To add it right click on empty canvas to open node popup, then select Root. Execution of BT starts here and goes from top to down, left to right.
Implementation note: All nodes and variables are in fact components, but they are invisible in inspector window. It is recommended to use separate empty game object to build the tree - this make it easier to create prefabs and avoid unnecessary unknown problems.
Most of nodes has additional properties that you can change. To do this select the node and list of options will show up in MonoBehaviourTree component inspector section (standard component inspector). When node setup is not valid, error icon will be shown next to the node. By default error is displayed if one of variable references is set to "None". You can create custom validation rules in your own nodes, see Node API section.
Editor Window Features
Right click on empty space to create new node. To connect nodes click on in/out handler (black dot on top and bottom of node), then drag and drop it above another node. In case node cannot have more than one child (decorator) the connection will be overridden by the new one. To delete, duplicate or disconnect nodes right click on node to open context menu and select the appropriate option. Use left mouse button to drag workspace or nodes. You can drag whole branch of nodes when CTRL key is pressed.
Component Reference
MonoBehaviourTree component
Main component used as hub of behaviour tree.
Properties
- Description - optional user description.
- Repeat OnFinish - whether the tree should be executed again when finished.
- Max Executions Per Tick - how many nodes should be executed during single update.
- Parent - parent reference if this tree is subtree. Read more in Subtree node section.
Node Inspector - Inspector of node selected in Behaviour Tree editor window.
Blackboard component
Component used to provide and manage observable variables.
To add variable fill the Key text field, select it's type and press "Add" button. Key is used as identifier to get or set variable value, this can be done by VariableReference or blackboard method: public T GetVariable<T>(string key).
Blackboard component displays all available variables in list and allows to set initial value for each of them.
Implementation note: Changing blackboard variables during playmode triggers change listeners, however old and new value will be the same in this event, because it's called from
OnValidate. Displayed values are refreshed every half second.
Built In variable types: Bool, Float, Int, Object, Quaternion, String, Transform, Vector2, Vector3. If you need to add your own custom type read Custom Variable section.
Master Blackboard option allows to make synchronisation effect between variables. When set, blackboard will replace variables during initialization, but only when their keys match. Replacement is not hierarhical and only variables from given parent blackboard are matched. It is recommended to create one master blackboard on top of the tree and keep all other subtrees blackboards synchronized with the top one.
Variables and Events
In most of situations nodes need to share some state data between each other, it can be done by Blackboard, Variable and VariableReference system. Variables are observale data containers, that can be accesed via Blackboard. To get variable you need to know its key, but inputting key manually to every node is not handy and very error prone.
To avoid this you can use helper class VariableReference. This class allows you to automaticaly get and cache reference to blackboard variable. VariableReference has also constant value mode in case you don't need to retrive values from blackboard. You can toggle VarRef mode in editor by clicking small button to the left. Keys displayed in dropdown will be loaded from blackboard on the same object or if there is none it will look upwards the hierarchy to find one.
// Get variable from blackboard by key
FloatVariable floatVar = blackboard.GetVariable<FloatVariable>("myKey");
// Attach listener to variable
floatVar.AddListener(MyVariableChangeListener);
// Create float reference property with default constant value
public FloatReference floatRef = new FloatReference(1f);
// Create int reference, but do not allow constant values
public IntReference intRef = new IntReference(VarRefMode.DisableConstant);
// Check if its in constant or reference mode
bool constant = floatRef.isConstant;
// Attach listener to variable reference
if (!constant)
{
// GetVariable will return null if floatRef is constant
floatRef.GetVariable().AddListener(MyVariableChangeListener);
}
// Get or set value of variable reference
floatRef.Value = 1.5f;
float value = floatRef.Value;
Important: TransformVariable change listener will be called only when reference to object changes. Position or rotation changes do not trigger change listener.
Custom Variable
If built in variables are not enough, you can create your own.
To create new Variable and VariableReference you must extend Variable class and VariableReference class. Variable inheriths MonoBehaviour, so to work properly it must by placed in file of the same name as your custom type. VariableReference is normal serializable class and can be placed in the same file. Add [AddComponentMenu("")] attribute to disallow adding variable component manually.
Any variable must implement ValueE
