Easy AI in Unreal Engine
As an aspiring Unreal Engine dev, I hit a serious road block when it came time to add AI to my game. After achieving a good grasp of blueprints and wrapping my head around UE4’s actors and controllers and other built-in classes, the idea of learning a totally new interface for UE4’s behavior trees was very discouraging.
Luckily, there’s another way! It’s flexible, it’s simple, and you can implement it entirely within blueprints. It’s called Utility AI.
In a previous article, I gave a general explanation of what Utility AI is and how it works. As a brief recap, Utility AI is a simple and effective approach to decision-making. With Utility AI, our NPC will:
1. List every action it could possibly do right now (attack, run, dance, etc.)
2. Look at the current situation (health, player defenses, nearby hazards, etc.)
3. Assign a score to each action
4. Perform the action with the highest score
For this tutorial, I’ll use one of the boss characters from a recent project as an example:
The Bug Queen can choose one of three actions (or “tasks”):
1. Wait (or Idle)
2. Attack (with a Laser)
3. Spawn some minions (or MakeBug)
How do we teach this Bug Queen to choose the right tasks at the right time? All we need is two new classes; UtilityTaskManager and UtilityTask.
UtilityTaskManager
UtilityTaskManager is an ActorComponent that can be added to any Controller. Its job is to choose a new task at some regular interval. Here, we’ve attached it to our Bug Queen Controller, and it will choose to execute one of the three Bug Queen Tasks every 0.5 seconds. Let’s look at the code:
First, we set up the possible actions using the TaskTypes array.
Every 0.5s, the UtilityTaskManager loops through the Tasks, scores them, and executes the winner. If a Task is going to take longer than 0.5s, it can deactivate the UtilityTaskManager to stall for time.
But what goes into the TaskTypes array? And how do we define the Idle, MakeBug, and Laser tasks for our BugQueen?
UtilityTask
UtilityTask is an Object that we will extend to define each task.
The three Bug Queen Tasks we need to make (BQT_Idle, BQT_MakeBug, and BQT_Laser) will all inherit from UtilityTask.
UtilityTasks are just an Object with some predefined functions:
1. Construct: Setup called when the NPC spawns.
2. Score: Rate task from 0–1. The NPC performs the highest-scored task.
3. Start: Called when the task begins.
4. Cancel: Cleanup called when the NPC switches to another task.
A Character-Specific UtilityTask
To define the tasks that our NPC can do, we first extend UtilityTask into a character-specific task class. BugQueenTask extends UtilityTask by adding variables for the queen’s controller and pawn. It overrides the Construct function of UtilityTask to set up those variables.
Defining Each Task
Next, we extend BugQueenTask into classes for each of the three possible actions. For this article, let’s take a look at BQT_Laser.
BQT_Laser overrides the Score and Start functions from UtilityTask. We score this task based on time since the last laser. On start, we call an event on the controller to fire the laser.
Multi-Frame Tasks
You may have noticed MFT_Laser, the controller event we called to fire the laser. Here, “MFT” stands for “Multi-Frame Task”. The laser will fire for a few seconds, which means the BQT_Laser task will take multiple frames to complete. We put the code for MFT_Laser inside the controller because the controller has access to async functions like MoveComponentTo, and timelines which make timing our multi-frame task much easier.
When the laser attack starts, we pause the UtilityTaskManager to stall for time and resume when the attack is done.
Conclusion
In this article, we introduced two new classes as the foundation for a Utility AI system in UE4. By adding a UtilityTaskManager component to our NPC, and extending UtilityTask to create some unique actions, we have a boss character that can present a real challenge to the player.
Here’s why I like this approach:
1. All blueprint. No behavior trees/blackboards
2. Every task is separated into its own file
3. Still gives you full access to the character controller
4. Can easily add Utility AI to any NPC when you need it.
Hopefully this concrete example shows you how relatively simple it is to set up a Utility AI system. From here, we could continue to create more Tasks for our Bug Queen, or create a new UtilityTask child to start forming an AI brain for a completely different NPC. And we did it all without leaving the comfort of blueprints!