Sunday, April 23, 2017

Unreal Engine: Creating AI Behavior Part 1

When You Need AI in Your Game

Unless a designer is creating a game that is strictly multiplayer, with no non-player characters whatsoever, they are going to need to design some sort of intelligence to control NPCs. This can range from simple background characters moving around the scene to provide some ambiance to enemy characters intent on stopping the player from achieving their goal. Unless the intention is to place statues in the game, AI will need to be addressed by the designer. 

Simple Behaviors

In some cases, AI can be very basic. Such as the example stated above where NPC characters are simply moving around the scene. Perhaps a designer has a scene in a small town and wants to add some villager characters to move about in order to make the scene appear more realistic. In this case the NPC characters can be programmed with some very basic logic to have them move around the village. Essentially these characters will have only one function, so only a single function needs to the programmed. The designer could use the Blueprint Based Task (BTTask) node in Unreal Engine to create the movement for the characters. There are several ways to design to logic for movement. My personal solution would be to have the character select a random location within the certain radius and then set that location as a destination for the character to move to. I will provide detailed the logic for this type of task in Part 2.

Complex Behaviors and States

To have an NPC perform more complex behaviors, a designer will have to program much more logic. As an example, say there is an enemy character in the level that has two functions, first to patrol an area and second to attack any player characters who come within range of their vision. Thus, at different times the enemy character will be doing different things. How does the enemy character determine what it should be doing? 

This is where player states and behavior trees come into play. With our enemy character there will be two states it will be in at any given time, either patrolling or attacking. Based on what "state" the character is in, the behavior tree will tell the enemy character what tasks to perform. The designer will need to set the enemy characters default state, and then set conditions to change the state of the character in order to change its behavior. 

Enemy Patrol Character Example

We will need a few prerequisites for our enemy character to move around the level. Most importantly a NavMesh (Navigation Mesh Bounds Volume). For any object to move in Unreal Engine, its needs to know where it can move. This is provided by placing a NavMesh into your level. For the example, I assume your have already created a level and are ready to place characters. In this example I will be using an outdoor level I created for my 3D Design class. 

From the left pane, select Volumes and scroll down to Nav Mesh Bounds Volume and drag it into your level. Once it is in your level, scale it to the size that is needed. You will want to make sure that the volume intersects with any surface you want characters to be able to move across. So you will want to move it slightly below the surface. Also make sure that the volume is tall enough for your characters height. In my case the enemy character uses the standard third person character skeletal mesh and only walks or runs. So my NavMesh only needs to accommodate the height of the enemy character.

NavMesh in Unreal Engine
You can use multiple NavMesh volumes in a single level. In the level shown I have used three NavMesh volumes to ensure that my enemy characters don't accidentally tumble into the gorge that runs through the middle and will only cross on the bridge. Using multiple volumes also allows you to prevent NPC characters from going to an area where you don't want them to be. Hitting P while in the viewport window will display the NavMesh volume and ensures that it is intersecting the surfaces you want, as shown by the green color. Normally the volume will be hidden from view. Hitting P again will hide it from view again. 

So now that the engine knows where characters can move, its time we set to creating some. I will call our character AI_Patrol and create a new Character Blueprint for our enemy. I set it to use the ThirdPerson skeletal mesh and movement animations included in the Third Person template in Unreal Engine. I will need to add some additional components to the character which will be shown in Part 2.

To start working on the enemy character's behavior we are going to use Unreal's AI Blackboard to create some variables that we will need. From the Content Browser select Add New select
Artificial Intelligence and then select Blackboard. Open the blueprint editor for the Blackboard by double-clicking it in the Content Browser. I am going to create three new keys:

Dest - a vector variable which will be used to set the character's destination

isChase - a Boolean variable which will be used to set the enemy character's state

SelfActor - an object variable used to set a target object

Blackboard Variables
To create the keys select New Key from the top and then select the type of variable from the drop-down name and give it the appropriate name. For the Dest and isChase variables, the type of variable and name is all that is needed. For the Self-Actor variable, we also need to make an additional change the base class option. After naming it, expand the Key Type setting in the right pane and change the Base Class from Object to Actor.

Next we will create the Behavior Tree, which will tell the enemy character what to do based on its current state. From the Content Browser select Add New select Artificial Intelligence and then select Behavior Tree. Open the blueprint editor for the Behavior Tree by double-clicking it in the Content Browser. The base behavior tree will only have a root node to start. 

We need to give it some decision making ability. Add a Selector by right-clicking and typing Selector in the search box. Add it to the blueprint and connect it to the root node by dragging a line between them. The selector is what we will branch from to make our decision on what behavior to perform.

We will now add a Sequence for each of the behaviors. Right-click and type Sequence in the search box. Add two sequences and connect each to the selector. The sequences will be based on the isChase variable from Blackboard. To tie these sequences to the Blackboard variable we add a Decorator to them. Right-click on one of the sequences and select Add Decorator and choose Blackboard from the pop-up menu. You will now see an additional box inside the sequence. Click on Blackboard Based Condition in the sequence. Options for the Blackboard Condition will appear in the right pane.

The isChase variable we created in Blackboard is what we will use to set the enemy character's state. The character will either be chasing or not chasing. Based on these states the character will perform a defined task. For the first sequence we will set tasks for when the enemy is not chasing. Set the following settings:

Flow Control
Set Notify Observer to On Result Change
Set Observer Aborts to Self

Blackboard
Set Key Query to Is Not Set
Set Blackboard Key to isChase

This is basically setting this sequence to perform the attached tasks when the enemy's isChase state is set to false.

On the second sequence we will set it to perform attached tasks when the isChase is set to true. Right-click the second sequence and choose Add Decorator and select Blackboard. Click on Blackboard Based Condition in the sequence and set the following settings:

Flow Control
Set Notify Observer to On Result Change
Set Observer Aborts to Self

Blackboard
Set Key Query to Is Set
Set Blackboard Key to isChase

So now we have a decision branch to choose what the enemy character does when the state of the character changes; one task if isChase is set to true, and another if isChase is set to false.

Behavior Tree Based on Blackboard Conditions

You may notice in the figure above that the tree has tasks defined below the sequences. These are Blueprint Based Tasks I have created for our enemy character which I will detail in Part 2. The AI_Movement task tells the enemy character to patrol an area by selecting a location within a certain range of the current location and then moving to that location. The task also adds a delay before moving so that the enemy character appears to pause before moving to next location; as though it is scanning the area. The AI_Chase task tells the enemy character to pursue the player character if they come within range of the enemy characters vision. Logic for both of these tasks will be detailed and will show how the enemy character's state changes based on conditions set in the tasks. 

As always I hope that you enjoyed this post and are looking forward to next. 

- End of Line



No comments:

Post a Comment