This integration package can be downloaded on the downloads page.
The Opsive Character Controllers are integrated with Behavior Designer allowing your AI to perform any function that a player-controlled character can perform. The Ultimate Character Controller integration contains a demo scene that is designed to work with both shootable and melee weapons.
When the integration is imported there will be four sample scenes included:
- First Person Melee Scene
- First Person Shooter Scene
- Third Person Melee Scene
- Third Person Shooter Scene
The behavior tree for these four scenes are exactly the same and the only difference is the player perspective and which weapon the characters have equipped.
When you are creating a new character that should be used with Behavior Designer ensure you have enabled AI Agent within the Character Manager. If you are using Unity’s Navigation Mesh you should also enabled the NavMeshAgent toggle.
After the character has been created the following components should also be added:
- Behavior Tree
- Behavior Tree Agent
The Behavior Tree Agent component can be found within the Opsive Character Controller integration package. In the demo scene you’ll notice that there is also a Demo Agent component added which adds the character’s health and ammo as property’s for Behavior Designer’s Property Mapping feature.
After the character has been setup it’s time to create your own behavior tree. The included behavior tree provides a great overview of the behavior tree flow so the rest of this document will describe how that behavior tree works. In order to get the most out of Behavior Designer it is highly recommended that you create your own behavior tree.
The included behavior tree will perform the following functions:
- Attack if the player is within sight.
- Attack if the player attacks the agent.
- Move towards the audio source location if a sound from the player is heard.
- Search for the player if the player is lost.
- Get health if needed.
- Get ammo if needed.
- Patrol if no other actions are necessary.
The entire behavior tree looks like:
Behavior trees evaluate from top to bottom, left to right. This means that the very first task that runs is the Sequence task directly beneath the Entry task:
The Sequence task is a Composite task that will evaluate all of its children until a child returns a status of failure. The Sequence task can be thought of an AND between the child tasks. The first three tasks that this Sequence task will execute relate to resetting the behavior tree to get it ready for the next run. The variables that these tasks are resetting will be described later. A Parallel task is then used to execute multiple children at the same time. There are two branches that this Parallel task will execute:
- Left branch which will perform the actual actions such as the movement or attack.
- Right branch which will keep the player’s location up to date when the Update Position variable is true.
The main functionality of the tree is contained within the left branch:
This branch is parented with a Repeater task which is set to Repeat Forever. The Repeater task is a Decorator which will keep executing the child branch for as long as requested. Since Repeat Forever is enabled the Repeater will keep the branch active until the bheavior tree ends. A Selector is parented to the Repeater. The Selector task will execute its children until a child returns success. The Selector can be thought of as as OR between the child tasks.
Because behavior trees evaluate from left to right the branches on the left have a higher priority than those on the right. This means that the very first branch that will execute is the branch that checks to determine if the agent is out of ammo:
The Sequence task of the ammo branch has a Lower Priority Conditional Abort set. Conditional Aborts allow the behavior tree to reevaluate child Conditional tasks when other branches are active. If the character is out of ammo then the character can’t do anything so this branch has the highest priority. If a lower priority branch (any branch to the right of the ammo branch) is active and the agent runs low on ammo then the conditional abort will abort the lower priority branch and start executing the ammo branch.
The ammo branch is a relatively simple branch that first checks to determine how much ammo the character has with the Int Comparison Conditional task. This Int Comparison task will compare the agent’s ammo to a constant number. The amount of ammo is retrieved through the Ammo property mapping setup through the Demo Agent component. If this amount is less than the constant then the Int Comparison task will return success and the branch will execute.
If the agent is low on ammo then it will stop aiming through the Start Stop Ability task. This is a task created for the Ultimate Character Controller and it will start or stop an ability based on the values specified. In this case the task will stop the Aim ability because the character shouldn’t aim when retrieving ammo. Another Start Stop Ability task is run and this task will start the Speed Change task so the character will start running towards the ammo location. The Seek task (from the Movement Pack) will use Unity’s navigation mesh to move the character to the specified position. After the character has arrived at the position the Start Stop Ability task is executed again only this time it will stop the Speed Change ability so the character will stop running.
If the agent doesn’t need ammo then the next highest priority branch is the Can See branch. This branch contains the main action in that it will actually attack the player when the player is within sight. Similar to the Ammo branch, the can see branch uses a Lower Priority Conditional Abort so it will abort any lower priority branch. The Can See branch will be able to abort any branches to the right of it, which means that it will not be able to abort the Ammo branch because the Ammo branch is to the left of the Can See branch.
The first task within the Can See branch is the Can See Object task from the Movement Pack. Can See Object will use a layer mask to search for any objects within sight. The player is on the Character layer so the task will only search for objects that are on that layer. Once the task finds the player the Is Alive task executes which will determine if the player is alive. There’s no need to attack a dead character. The Set Shared GameObject task is then a helper task that will transfer the found Can See Object value to the Target variable. This is done so when other tasks operate on the found player variable the original object isn’t lost. Two Set Bool tasks are then executed which indicates that the agent should wander if the player is lost and that the target’s position should be updated. The right branch under the original Parallel task will then set the target’s position to the Last Position variable.
A Selector task is then run which will first evaluate the left branch. The goal of the left branch is to attack the target for as long as the target is in sight. To accomplish this a Sequence task is used with the Self Conditional Abort. The Self Conditional Abort is a new abort type and this abort type will reevaluate the Conditional task for as long as the current branch is active. In this case the current branch contains the Is Alive task along with a Selector so it will reevaluate Is Alive for as long as the agent can see the target. The Is Alive task will return failure when the target is no longer alive.
The first branch that the Selector task will evaluate has a Parallel task as the parent. This Parallel task runs two branches:
- The left branch attacks if the target is within sight
- The right branch will keep the agent near the target
The left Attack branch uses another Can See Object task to determine if the agent is near the target. This Can See Object task is different from the first Can See Object task as it has a smaller distance magnitude so the agent will only attack when near the target. If the target is near the Start Stop Ability task will execute to keep the character aiming. After the agent is aiming the Start Stop Use task will execute which will actually use the item, which will either fire the assault rifle or swing the sword. A Wait task is then used to prevent the agent from trying to attack every frame.
While the Attack branch is running the Move Towards branch will also run. This branch contains two parts:
- Move into position after first acquiring the target.
- Stay in position after arriving in position.
To move into position the Within Distance task is used to determine if the agent is within distance of the target. A Self Conditional Abort is used so the Within Distance task will reevaluate for as long as any tasks within the current branch are active, in this case it will be the Seek task. As soon as Seek moves the agent close to the target the Within Distance task will return success and the Inverter will change that success to a failure so the branch will then stop executing. While the Seek task is active the Speed Change ability will be activated so the agent will run towards the target.
After the agent has move to be within distance of the target the right branch will keep the agent near the target. There are three main differences between this branch and the previous Move Towards branch:
- The current branch will have the character walk instead of run while seeking the target.
- A Can See Object task is used in addition to Within Distance so the agent will always be in sight of the target while attacking. As an example the target may move inside a structure which would cause prevent the agent from seeing the target even though the target may still be near the agent.
- An Idle task is used if the agent doesn’t need to seek into any position. If the target is standing still and is within sight then the agent can keep attacking without having to change positions.
The agent will now attack and move towards the target while within distance. If the target gets away from the agent and moves too far away then the right Move Towards branch will return failure and execute the Reset branch. This Reset branch runs two Actions which will ensure the agent is no longer attacking and is no longer aiming.
When the target was first acquired the Wander and Update Position variables were set so the agent will search for the target if the target is lost. If the target is killed by the agent then there is no need for the agent to wander so the Target Death branch will reset all of the attacking related variables back to the default.
If the agent doesn’t need to get ammo and the player is not within sight then the next highest priority branch will run. This branch uses the Ultimate Character Controller’s event system to determine if the agent has taken damage. If the agent has taken damage then the Has Taken Damage task will return success and the branch will execute. When the agent has taken damage the branch will first get the position of the object that it took damage from and set Wander to true. Before the agent moves towards the target it will first determine if their health is critically low. If the health is critically low then the agent will seek towards a health pack.
After the agent has either retrieved a health pack or determines that more health is not needed the branch will end. Remember that the Wander variable was set to true so the Wander branch will start executing if there are no more higher priority branches.
The next highest priority branch is the Can Hear branch. This branch uses the Can Hear Object task from the Movement Pack to determine if any audio sources are emitted a sound. If any audio is heard then the agent will run towards the audio source position by starting the Speed Change task and using the Seek task to move into position. The Wander variable is also set to true so the agent will wander if the target can’t be seen by the time the agent arrives at the Seek location.
Throughout the execution of the tree there have been multiple cases where the Wander task was set to true. The Bool Comparison task will compare this Wander task variable to true to determine if the agent should wander. Before the agent can wander they first have to Seek to the Last Position. This variable will be set whenever the Update Position variable is true and it will indicate the last position that the target was located. When the agent arrives at the Last Position the Wander task will then execute which allows the agent to search for the target.
Remember that during this time the higher priority branches are being reevaluted so if the player comes within sight of the agent at any time then the Can See branch will abort the current branch so the character can start to attack. The Wander task is parented to the Parallel Selector task which will execute all children until a child returns success. To the right of the Wander task is the Wait task which will return success after a predetermined duration. This will prevent the agent from wandering forever and put a cap to the amount of time that the agent wanders.
If no other branches need to execute then the tree will fall back to the Patrol branch. This branch will move the character between patrol points and keep the character moving until a higher priority branch aborts it.
As the Ammo, Can See, Taken Damage, Can Hear, Wander, and Patrol branches are executed near the top of the tree the Update Position branch will also execute. This branch will update the position of the target when the Update Position is true. This branch is separated out from the rest of the tree because not just a single branch can set Update Position to true so to prevent having to add the same tasks multiple times this branch has been added near the top under a Parallel task.
Now that you’ve completed this overview you should have enough knowledge to get started to create you own tree with the Ultimate Character Controller. Make sure you go through the demo tree a few times to get familiar with Behavior Designer’s visual editor.