Converting my basic guard AI from the Godot engine into Unreal Engine was an interesting challenge. There isn’t a whole lot of built-in AI functionality in Godot so I needed to create a system that allowed environmental queues such as what is visible and what can be heard.
Source code examples for the project are available here.
To accomplish this in Godot, I started by setting up a high level environmental signal handler that resided in the base level node. It functions as the main mechanism for distributing noises to those who are interested. It was designed to be simple and extendable to allow me the flexibility to quickly prototype new ideas. Currently it allows the player to “create noises” by calling the relevant function on the top level node.
Guards that are loaded in the level can register for the sound notification signal on the top level environmental signal handler. This way the player and the guards can remain decoupled. Whenever the player creates a noise, the top level node distributes the notification to anything that has registered for the signal. This functionality very closely mimics the boost signals library which I have used extensively.
When deciding how the guard AI should be moved into Unreal I decided to utilize the benefits of working with a mature engine. That meant diving into Blackboards and Behavior Trees
Putting together quick logical flows using Behavior Trees is quite intuitive. In the above image you can see how the guard’s AI works.
Essentially the guard is either wandering around between waypoints or chasing the player when he either hears or sees them.
The logic within the actual guard class is fairly simple. Whenever the guard either hears a noise or sees something, it checks to see if that Pawn was the player. If it was then the guard sets their MoveToTarget to be the player and starts their pursuit.
In the short clip below you can see when the guard “notices” the player by the blue debug line that is drawn. The guard then quickly changes direction and heads towards the players location.
Setting up the Behavior Tree tasks was a little more interesting.
First of all, Unreal does not behave well with task classes that do not follow their naming conventions. The engine appears to take everything after the underscore in the class name and use that as the function name that appears in the Behavior Tree graph. As long as you keep the desired task name after the underscore then you shouldn’t run into any issues connecting Behavior Tree nodes to C++.
If the class were named something like “FindWaypoint_BTTask” then there would be a task named “BTTask” in the Behavior Tree editor. Obviously this isn’t very helpful when trying to add new tasks to the graph. It is best to keep the task name on the right side of the underscore so you can easily find the correct task when creating your graph.
The guard starts by finding a waypoint. This is simply a Target Point that has been placed in the level. The guard picks one of the available target points at random then sets the corresponding Blackboard Key.
After the guard has picked a waypoint, they then choose a location near that waypoint to travel to. This helps to make the guard movement appear slightly more random and less predetermined.
With all of that in place the guard is able to freely chase the player around whenever they get too close.
For now the guard’s movement leaves a little to be desired. For one, the guard shouldn’t be turning like it is. This turns the sprite which makes it invisible to the camera. For more details on my plans to extend the Movement Component for 3D sprite motion check out the Player Movement post.