Behavior Trees In Unity
Creating a Behavior Tree with Scriptable Objects
This is a a version of the Behavior Tree Created by the KIWI Coder.
I have already talked about the Strategy, Decorator, and Composite patterns and built a simple Ability System along the way. Now I am going to look at building a Behavior Tree using UI Builder, GraphView, and Scriptable Objects in Unity 2021.3.1f1; any version of Unity 2019.1 or newer will work, 2020.1 or newer to use the UI Builder. The Graph View is what is used in Shader Graph, The Animator window, and other node based editor windows in unity.The concepts here can be used to create any node base tree view editor window. Some examples would be Behavior Trees, Custom State Machine System, or even the Ability System from my previous articles.
Behavior Tree Concept
Behavior trees are a formal, graphical modelling language used primarily in systems and software engineering. Behavior trees employ a well-defined notation to unambiguously represent the hundreds or even thousands of natural language requirements that are typically used to express the stakeholder needs for a large-scale software-integrated system.
My Behavior Tree is an execution tree (uses the Strategy pattern) and always starts with a Root Node. This will be so that the behavior tree knows where to start. Root Node has only one child. Now there are 3 basic main type of nodes Decorator, Composite Node and Action Node.
Each Node can return one of three states Running, Success, or Failure.
All nodes will be saved in Unity as Scriptable Objects. A Behavior tree will be a Scriptable Object containing all the Nodes in it.
Creating the Behavior Tree
Now that I know what my behavior tree is going to look like I need to create it.
The Node
The first thing that I will need is to define what a Node is. All of the Nodes will be a Scriptable Object. The reason I am using Scriptable Objects is that I know that I am going to build an Editor to Edit the Behavior Tree, this Editor will be using UXML and Serialized Object data binding which has specific requirements. so I will make node an abstract class so I have to create sub-types of this and can’t create it directly.
Next I will define the states that the Node can be in as an ENUM.
I will also need to keep track of whether this node has started or not.
Now I need to create the Abstract Methods that every node has to implement.
Now I need a way to make the Node Update and get the State that the node is in.
The completed method looks like this.
I then inverted my running check it makes the code look cleaner in my opinion.
The Behavior Tree
Now I can create my Behavior Tree.
Now I need a way to create the Behavior Tree, I will use the Create asset Menu Class Attribute. I did not do this with the Nodes because the Behavior Tree Editor Window will be responsible for this.
Now The Behavior Tree Needs the Root Node, the entry point.
It needs a Node State to represent the entire state of the tree.
Now I need an Update Method that mirrors the Nodes. It should return failure if there is no root node. If the root node is running then it should update the root node, set it’s state to be the state to be the root nodes state and return the State that the tree is currently in.
Node Sub-types.
Now I need to create the 3 Node Sub-types, Decorator Node, Composite Node, and Action Node. All of these are Abstract Nodes. The Interface, Abstract members will be implemented on the individual Action Nodes that inherit from these node types.
Decorator Node — has one child and is capable of augmenting the return state of it’s child. This uses the Decorator pattern.
Composite Node — has a list of children and is the control flow of the behavior tree like switch statements and for loops. There are 2 types Composite Nodes the Selector and Sequence. This uses the Composite pattern.
Action Node — the Leaf of the tree, has no children, and is where all of the logic gets implemented.
Debug Log Node — Action node that logs a message.
Now All I need to do is have a Message to log and fill in the Methods. In the Update method I will return The State of Success since there is no way that this node can fail.
Creating and running the Tree
Now I have enough created in order to create a MonoBehaviour that runs my tree.
I need to keep track of the Behavior Tree that I am running.
Now I need to Update The Behavior Tree.
For now I will create the tree in the Start Method. The tree needs a root Node to run so I will Create a Debug Log Node and add it to the tree as the root node. I will change this latter, I will have an Editor that for Editing Behavior Trees.
In Unity I created an empty Game Object in the Scene and added the Behavior Tree Runner Component to it.
Now when I run the project the Behavior Tree runs.
Make things more interesting.
Lets make this tree more interesting by adding some other node types.
Repeat Node — A Decorator Node that augments the return state of it’s child to be Running.
I could do anything I want with this repeat node, add variables for the number of times to repeat, repeat until the node fails, or repeat until the child node succeeds.
I can add this to my Behavior Tree Runner in the Start Method
My Tree will run forever.
Sequencer Node — Composite Node that Runs all of the children in Sequence.
For the On Update Method, if any of the children fail then this node should fail, if all the children return success then this Node returns Success, if there are no children return Failure, if the child state is an unrecognized state return Failure.
Now the fancy if statement with the switch expression is the same as :
To use this new node I just added it to the Behavior Tree Start Method
Selector Node — Composite Node that selects one of it children to run based on some condition.
Wait Node —Action Node that waits for a period of time before returning success.
Now when I first did this I used delta time instead of time and my wait node did not work correctly. This is the importance of testing.
What’s Next
Now that I have my behavior Tree created and working it is time to build a way to create and edit my behavior trees. As this article is longer then I expected stay tuned for Part 2 where I build an Editor to edit my behavior trees, like we can Edit the Animator Controller.
Get The Code.
As always my code is on GIT HUB.