Overview:
As you may have noticed, I fell a bit behind on posting to the blog, so I’ll catch up on what I’ve been working on! The past two weeks have been focused on developing a framework for the enemy’s artificial intelligence. We decided to use behavior trees to contain the logic for each of our enemies. This post will cover the general layout for the behavior tree.
Behavior Trees:
The behavior tree contains sequences which contain the main behaviors. These sequences / behaviors are similar to states. The behaviors are composed of multiple leaves / tasks which do exactly as they sound: they take care of the smaller tasks needed to perform a full behavior. These tasks, when paired together, compose the core logic of the AI. These tasks can be combined in different orders and used in various behavior sequences to create new logic, making them much more reusable than states found in a state machine.
AI Navigation:
An example of a behavior tree is the patrol sequence used in all of the enemies in the game. The way I decided to implement the AI navigation is through the NavMeshComponents which allows me to quickly do the following:
Bake a mesh that different characters / enemies can navigate on.
Quickly add barriers that certain enemies can traverse while others can’t.
Quickly create the shortest path to a destination while avoiding obstacles, all from a single function call.
Using these components I have set up the simple behavior sequence with the following three simple tasks:
Check if at destination: This will check if the enemy has reached the destination point. This task can also be reused for flee points, cover points, etc.
Set a destination point: This will randomly set a destination point for the enemy to move to. This point is controlled from a central position in the patrol area, allowing for multiple enemies to have a central position to pull from.
Move to destination: This is a direct call to the NavMeshComponents. This will generate the shortest path to the destination and move the character accordingly.
Each of the individual tasks handles more complex code, but having the code broken down into tasks makes the whole behavior tree much more legible.
The individual tasks look similar to the code snippet below:
Once the tasks are fully written out, we can simply reuse the tasks in different branches of the tree. The following code snippet is an example of how the patrol is done for almost all of the enemies in the game.
Moving Forward:
In the next blog post I’ll cover a bit more on the different branches of the behavior tree and how we can use clever tricks to navigate around the tree. I will also cover how we can make the AI more realistic through manipulating coverable objects with the nav mesh and making the AI more intelligent.
Comments