
Project Description
The possible decisions of an AI are represented by selectors and sequences in a behavior tree. The selection of a behavior with this method is often binary, the behavior tree can quickly become complex, and the definition of different behaviors is therefore unintuitive. In behavior trees or state machines, only one consideration is often considered before moving on to the next one in a fixed order.
The Utility AI principle allows the definition of actions, considerations, and decisions. These can be defined intuitively by a game designer. An action defines a possible behavior of the AI, for example ranged combat. An action consists of any number of considerations, which has an influence on the probability that the AI chooses this action. Possible considerations for ranged combat are the distance to an opponent or the number of arrows. The input values of the considerations are normalized, the output of the considerations is multiplied and results in an action score. This enables a comparison of all possible actions. The optimal action that has achieved the highest action score is therefore getting selected. If an action is selected, then the decision associated with this action is executed. The decision represents an actual function in the game world, e.g. shooting an arrow.
Through the implementation of the Utility AI system in Unreal Engine, it turned out that a hybrid of this approach and behavior trees can achieve an optimal result. The strength of the Utility AI system is the selection of a possible behavior, while the execution of the selected behavior can be more easily defined by a Behavior Tree.
To enable a fun small game to test the AI, a small RPG system was implemented. The player can do stealth, ranged or melee combat. The goal of the game is to sneak or fight your way inside a castle, steal the guarded crystal and drop it off at a specified location.
My Role
Development of an Unreal Engine Plugin, which allows the creation of an AI based on the Utility AI system. The algorithms and functions to create and process the Utility AI were implemented in C++ and Blueprints. Other gameplay logic like the stealth, ranged and melee combat was also implemented in C++, some functions were exposed to Blueprints to allow a quick iteration of features.
Most of the models in the levels were from the free Epic Games content, some assets like shields, bows, ivy and shrubs were modelled in Blender. The heightmap for the landscape was created in Gaea and then imported into Unreal Engine.
Git and GitHub was used as version control system, while YouTrack was used as issue tracker.
Notable Features
- A custom Unreal Engine plugin that allows the visual, graph-based creation of the AIs actions, considerations and decision required by the Utility AI system to control NPCs. Editor graph based on the Generic Graph Plugin, but extended to allow creation and definition of actions, considerations and decisions.
- Extensive C++ base class implementation with Blueprint exposed C++ functions.
- Algorithm that accepts different types of information and outputs the relative benefit of a behavior.
- Day and night cycle that influences the AIs decision making.
- Multiple different combat stances: stealth, melee and ranged.
- Spline system to let level designers visually define a NPC patrol route.
- Custom landscape created with Gaea and small castle as playground for the player and the AI.
- Sequencer animation as level introduction.
Project Difficulties & Solutions
- While the behavior (the actions) of the AI was selected by the utility AI system, the actual implementation in the game world was implemented exclusively through Blueprints (and sone C++ exposed functions). This made the implementation of more complex behavior confusing and time-consuming. Therefore, the Utility AI system is recommended for selecting a behavior, while the Behavior Tree can be used to implement and execute the selected behavior.
- In the character controller of the NPCs, a utility AI graph asset can be selected to control the AI. Because this graph is not instantiated, all AIs share the same input and evaluation of the graph, overriding each other’s behavior. The Behavior Tree uses the UBrainComponent class to instantiate the Behavior Tree graph. In order to instantiate my own utility graph, an attempt was made to derive from this class in C++ and to overwrite some functions. As a result, however, another class could not be initialized correctly for unknown reasons. As a workaround and due to time constraints, a separate Utility AI graph had to be created and assigned for each AI character.