Behaviour Tree
For this project, I took on the task of implementing the behavior tree system, which involved creating the tree, nodes, and the gameplay logic for the enemies.
The tree needed to be interruptible from both external sources and from within the tree itself. Its nodes share all data through a blackboard, which is owned by the tree.
To make the behavior tree reusable in future projects, I decided to split it into two parts: one for the game engine and one for the project. This approach ensures that the engine part remains independent of the project-specific behavior nodes.

Part of the planned behaviour tree for this project.
(Graph Created in Miro)

Game Engine Nodes
Composite nodes were created to operate as intended without needing additional logic to be implemented once instantiated. These include the sequence and selector nodes.
Decorator nodes, however, required some project-specific logic, so they were designed with a simple interface that allows for logic to be added after instantiation. These nodes became the decision and condition nodes, which can be given a predicate and operate based solely on that predicate.
Leaf nodes can range from simple behaviors to entire subtrees connected to them. For this project, the only node used was the Action node.
Action nodes contain the actual behavior of the AI. These are the nodes inherited when creating project-specific behavior nodes.
The nodes return an ongoing status every frame, and the tree tracks the currently running node. It returns to that node if no decision or condition has changed since the last frame. This design required the nodes to be able to reset if needed. If an interrupted status is returned from a node, the tree runs the inherited reset function on all nodes. For example, when the enemy discovers the player during patrolling, the tree can reset. The tree can also be reset through an external call to the enemy's interrupt function, which triggers a reset through the tree, such as when the enemy takes damage. Thus, reset logic can be implemented for each node if desired.
Project Specific Tree & Nodes
To create a behavior tree for an AI in the project, I created a subclass of the behavior tree from the engine for each AI type and then manually construct it to achieve the desired behavior.
The action nodes execute their action when they are reached through the tree, performing the gameplay logic for the AI.

Top: Construction of the project behaviour tree.
Bottom: Initiation of a project specific action node.

AI - Behaviour
Patrolling & idling
The basic behavior of the enemy in this project included simple patrolling and idling while trying to detect the player. I wanted the level designers to have control over this behavior in the editor so they could use it to build suspense. So, along with another programmer who implemented the visual scripting system, I was there to provide them with the tools they needed.
One simple tool allowed designers to set the patrol path for each enemy, as well as make it impossible for them to enter combat, which could result in unwanted behavior. The enemies could be used purely for visual effect, such as walking past a hallway further down or passing on the other side of a window.
The tool itself was simple and included a patrol point asset to be linked to the enemy. Designers could also set individual idle times for each point along the way, and choose whether the enemy should backtrack through the path, circle it, or stop at the last location and idle until combat was initiated.
The player detection system was also implemented, giving enemies a field of view and allowing them to "hear" the player running or firing a revolver behind them. They considered line of sight unless explicitly told to ignore it, which could be done through scripting.
Combat
Engaged in combat with a single enemy, it displays a very simple, common behavior where the enemy tries to reach you and attack if within range.
Combat with multiple enemies required a more intelligent behavior to align with our planned game design. The first part of this involved the use of
attack tokens so the player wouldn’t be overwhelmed or swarmed by enemy attacks. I implemented a token system within the enemy manager, where any enemy within attack range could request the token. If granted, the enemy would perform an attack and then return the token. The enemy manager randomized the token distribution among the requests. If an enemy holding a token was interrupted by an attack or moved out of range before attacking, the token would be returned, and the enemy would need to request a new one.
Additionally, I didn’t want the enemies to run into each other while chasing the player, so a separation behavior was implemented when multiple enemies were engaged in combat.
I also implemented a diminishing return system for interruptions due to taking damage, meaning the more frequently the player attacked an enemy, the higher the chance it would not be knocked back and interrupted. Without this, the enemy could easily be stunlocked during combat.
The work I did for this project solely involved the enemies and their behavior, including their animations with root motion movement, interactions with the player character, and working with the engine's event system to achieve the desired behavior.
Future Improvements to the Behavior Tree System
Events When Entering or Exiting a Node.
To avoid unnecessary calls to the sound engine and the skeletal mesh every frame while a specific node is running, this could be implemented in a function that is called only when the node is entered, rather than while it's running.
Parallel Running Paths.
There was no need to implement functionality for running multiple paths or nodes simultaneously in this project, but adding this feature would allow for more advanced behaviors.
Instant Return to Running Node.
The behavior tree currently runs through the entire path every frame which could claim performance when the tree grows. To improve this, the tree could track the currently running node and instantly return to it until it's completed. This would require a rework of the way the tree handles interruptions though.
Visual Scripting tool.
It would be a great way for game designers to have full control of the AI through visual scripting where they could construct a tree and implement behaviour. But for this project that would be out of scope.

You may also like

Back to Top