Enemy AI With C++ And Blueprints In Unreal Engine

Depending on the type of enemies you have in your game, you will create different AI behavior. And there are multiple ways how to create enemy AI in Unreal Engine, from the basic enemies that move between two points all the way to creating complex AI behavior using Behavior Trees and Blackboards.

In this post we are going to learn about AI in Unreal Engine by creating basic, intermediate and advanced enemy AI behavior using C++ and blueprints.

Download Assets And Complete Project For This Tutorial

Unreal Engine Enemy AI C++ And Blueprints Tutorial

To follow along with this tutorial, please download the starter project by clicking on the green Download assets button above.

In the downloaded folder you will find the finished project, and the starter project which I prepared for you to follow this tutorial.

Important Information Before We Start

One of the labels for this tutorial is beginner, however this is not a tutorial for complete beginners.

I expect you to know how to create basic games in Unreal, but you are a beginner when it comes to AI programming in Unreal. So it is mandatory that you know how to code in C++ and blueprints, and know how to use Unreal and its interface.

Another thing to note is that I am using Unreal Engine 4.27 for this tutorial, but the techniques that I am going to teach you can be applied to any Unreal Engine version.

Enemy AI Patrol

First we are going to create a basic patrol behavior for the enemy where the enemy is going to roam in the level.

Open the Enemy_AI_Starter_Project that you downloaded. Open the EnemyAI_Map located in Content -> Maps folder. In the map you will notice the enemy and the player actor are already prepared.

Open the BP_Enemy blueprint located in Content -> Blueprints folder. In the Event Graph tab, Right Click and search for custom event:

Img 1
Name the new custom event Random Patrol:
Img 2

To make the enemy patrol in the level, we are going to use AI MoveTo function, and we are going to provide it a random destination within the navigationable bounds volume:

Img 3

You can copy the nodes from here:

For AI MoveTo parameters we provided self, which is a reference to the enemy blueprint, and for the destination we used the GetRandomReachablePointInRadius which is a function that will give us a reachable point in the radius we provide from the origin.

This function will calculate all the collisions that are in the way of the AI and that way the enemy will cleverly avoid any obstacles in his path.

For the origin parameter of the GetRandomReachablePointInRadius function we provided the location of the enemy, because we are going to patrol from the enemy’s location.

For the radius I’ve set 1500 as the value, which means it will try to get a reachable point from the enemy’s location in the 1500 value radius. Of course, we can change the radius value to a higher or a lower number anytime we want to make the enemy patrol further in the level.

When the AI MoveTo function finishes, we are going to delay for 1 second using the Delay function, and then call the Random Patrol node we create so that the enemy will randomly patrol the level again.

Before we proceed to test this out, from the BeingPlay call the Random Patrol node we created:

Img 4
Compile and save the changes we made in the BP_Enemy blueprint. In order to make this work, we need to add the NavMeshBoundsVolume in the level. From the Place Actors tab, search for the NavMeshBoundsVolume:
Img 5

Drag the NavMeshBoundsVolume in the level and set the following values for its Location and Scale:

Img 6

This will make the NavMeshBoundsVolume cover the whole level and this will be the navigationable area where the enemy can move with the help of AI MoveTo function:

Img 7

Let us now run the game and test it out:

We can also remove the delay that happens after AI MoveTo function finishes which will make the enemy patrol the level without stopping.

Detecting The Player’s Presence And Moving Towards Him

We can use the same function to make the enemy run towards the player. But first, we need a way to detect the player’s presence near the enemy. For that we are going to attach a Sphere Collision component to the enemy.

In the blueprint editor for the BP_Enemy, in the Components tab click on Add Component and filter for sphere collision:

Img 8
Rename the component to Player Collision Detection and in the Details tab set the Sphere Radius to 800:
Img 9

In the My Blueprint tab, under variables create a new boolean variable and name it Player Detected. Then create another variable and for the variable type, click on the variable icon:

Img 10

In the search bar filter for third person and select the Object Reference for the Third Person Character:

Img 11
In this variable we will store a reference to the player actor since we need his location in order to make the enemy move towards him.
For that, we need to select the Player Collision Detection component in the Components tab, and in the Details tab scroll all the way to the bottom and under Events, click on the green + button for On Component Begin Overlap and On Component End Overlap:
Img 12

With these two functions we are going to detect when the Player Collision Detection sphere collides with the player actor so that we can chase him, and when the player actor exists the collision so that we can stop chasing him.

But before we do that, we are going to create a custom event and name it Move To Player, which is going to make the enemy move towards the player actor:

Img 13

You can copy the nodes from here:

As you can see, we are using the Player REF variable, which is a reference to the player actor in the game, to get the location of the player and make the enemy move towards him.

The Acceptance Radius parameter for the AI MoveTo function is how far from the target will the AI stop moving, in this case we set the value to 150 units.

To get a reference to the player actor, we need to detect collision in On Component Begin Overlap that we created:

Img 14

In OnComponentBeginOverlap we first perform a cast to test if the player actor has collided with the sphere, if that is true, we will get a reference to the player actor and we set the Player Detected bool value to true. We will use this variable to control the enemy AI logic.

And then, we make the enemy go towards the player using the Move To Player custom event node we created.

In OnComponentEndOverlap, when the player actor collides with the sphere, we are going to set the Player Detected value to false, and make the enemy patrol randomly again:

Img 15
You can copy the nodes from here:

Compile and save the changes and now let’s run the game and test it out:

While the enemy is detecting the player’s presence and going towards his location, we have one big issue, and that is the enemy is not following the player when he moves around, instead it goes towards the first location where the player was when we detected the collision with the player.

We can fix this issue by calling the Move To Player in the Tick event, but this will make a problem when we want to attack the player. Instead there is a better solution to this problem that we are going to implement now.

A Smarter Way To Make The Enemy AI Chase The Player

Since the AI MoveTo function will move the AI to the first position we pass to it, we need a way to test if the target position has changed so that the AI will move towards the changed position.

For that, I am going to create a new custom event, name it Seek player and add the following nodes to it:

Img 16
You can copy the nodes from here:
Seek Player will call the Move To Player which makes the AI move towards the player target, but it will also use the Set Timer By Function Name to call the Seek Player after every 0.25 seconds.
We specified that in the Function Name parameter where we passed the Seek Player, and for the Time parameter we set 0.25. Also, the Looping parameter is set to true, which means the Set Timer By Function Name will be called over and over after every 0.25 seconds.
Before we proceed, we are going to create another custom node that will make the AI stop seeking the player:
Img 17

You can copy the nodes from here:

The Clear Timer By Function name will stop the timer from calling the function with the specified name, in our case Seek Player which we provided in the Function Name parameter.

We need to do this because we specified that the Set Timer By Function Name should loop, which means it will run all the time until we stop it by using Clear Timer By Function Name.

Now, we need to edit the Move To Player function:

Img 18
You can copy the nodes from here:
Now, when the enemy reaches the player, it will test if the player is still within its bounds by checking if the Player Detected value is true, if that is the case it will continue chasing the player by calling Seek Player.
We also need to change the On Component Begin and End Overlap for the enemy:
Img 19

You can copy the nodes from here:

Compile and save the new changes to the BP_Enemy blueprint and let’s run the game to test it out:

As you can see now, even when the player changes his location the enemy is constantly chasing him.

Enemy AI Attack

Now that we have the chase logic in place, we can create the attack functionality of the enemy.
First we are going to create a new boolean variable and name it Can Attack Player, we are going to use this variable to control the attack logic of the enemy.
Next, in order to detect if the player is in the attack range of the enemy, we are going to create a new Sphere Collision component. Name the new Sphere Collision to Player Attack Collision Detection and in the Details tab set the Sphere Radius to 200:
Img 20
For the Event Graph, we need the On Component Begin and End Overlap for the Player Attack Collision Detection:
Img 21

The idea is when we detect player collision with the Player Attack Collision Detection component, we will set the Can Attack Player value to true, and when the player exists that collision we will set the value to false:

Img 22
You can copy the nodes from here:

We also need to make changes in the Move To Player node so that the enemy attacks the player when it gets close to him. First we are going to create a new condition when the AI MoveTo finishes:

Img 23

When the enemy gets to the player’s location we are going to check if the enemy can attack the player, if that is true we will call Stop Seeking Player because now we need to attack him, if the enemy can’t attack the player, then we will call Seek Player again.

To attack the player, we are going to use the montage animation I’ve prepared which is the enemy’s attack animation:

Img 24

You can copy the nodes from here:

The Play Montage function takes a few parameters that we need to provide. The first one is the Mesh which represents the Skeletal Mesh Component on which the animation will be played.

For that, I provided the Mesh component from the BP_Enemy:

Img 25

For the Montage To Player click on the drop down list and select the Mutant_Attack_Montage:

Img 26

When the montage finishes playing, we test if Player Detected is true, if that is the case we will make the enemy move towards the player by calling Seek Player and that will repeat this same process over again.

Compile and save the changes and let’s run the game to test it out:

Attaching Collision Components To Sockets

Now that we are attacking the player, let us also deal damage. To do this, we need to edit the skeleton of the mutant model. In the Content -> Enemy_Model folder open Mutant_Skeleton in the editor:

Img 27

In the options tab on the left side, locate the RightHand in the skeleton hierarchy and Right Click ->Add Socket:

Img 28
This will create a socket on the right arm of the mutant model:
Img 29
Now we can open the BP_Enemy in the editor, and in the Components tab, select the Mesh component and from the Add Component button filter for Box Collision:
Img 30

Rename the Box to Damage Collision, and in the Details tab under the Sockets settings for the Parent Socket field click on the little loop icon and search for the RightHandSocket which is the name of the socket we created in the Mutant_Skeleton a few moments ago:

Img 31
This will make the Damage Collision component a child of that socket, and we know that socket is connected to the right hand of the mutant model:
Img 32

This means that the Damage Collision will move along with the right hand of the mutant model. We do need to reposition and resize the Damage Collision component, so set the following values for the location:

Img 33

And the following values for the Box Extent axis under the Shape settings:

Img 34

Now the Damage Collision component looks like this:

Img 35

Animation Notification Events

The reason why we went through all of this Box collision and socket set up is because we are going to use the attack montage animation to trigger the damage functionality.

If we open the Mutant_Attack_Montage which is located in Content ->Enemy Model folder, and preview the animation we will see that the mutant is attacking with its right hand:

Since we attached the Damage Collision component to the right hand socket, when the attack animation is played and the mutant moves his right hand, the Damage Collision component will move along with it and we can use that to detect the collision with the player actor and deal damage.

To do that we need to add animation notifiers that will notify us when the animation is at a certain frame.

We can do that by dragging the animation preview slider at the desired frame in the animation timeline:

Img 36

Or we can set the exact frame we want on the right side of the Filter search bar in the animation timeline:

Img 37

When we are done with that, on the Notifies timeline, Right Click -> Add Notify -> New Notify and name the new notify Attack Started:

We created a new animation notify, or notification, on frame 11, which means when we play the attack animation and when the animation reaches frame 11, the Attack Started notify will be called, and we will be notified in the code when that happens.

We also need to create another notification that will inform us that the animation has ended. Go on frame 30, and create a new notify and name it Attack Ended.

After you finish, you will see two animation notifications in the attack animation timeline:

Img 38

Before we access the notification events in the blueprint editor, we need to go inside the BP_Enemy editor, and under variables create a new boolean variable and name it Can Deal Damage:

Img 39

Now open the BP_Enemy_Animation blueprint located in Content -> Enemy_Model folder. In the Event Graph tab, Right Click and search for attack started:

Img 40

In the same way search for the attack ended anim notify node. We already have a reference to the BP_Enemy in the BP_Enemy_Animation blueprint, so we can use that variable to access the Can Deal Damage bool to change its value when the attack has started and when the attack ends:

Img 41

You can copy the nodes from here:

Going back to BP_Enemy blueprint, select the Damage Collision component and in the Details tab under Events, click on the green + button for the On Component Begin Overlap:

Img 42

In the Event Graph tab, for the On Component Begin Overlap of the Damage Collision component, add the following nodes:

Img 43

You can copy the nodes from here:

When the Damage Collision component detects the collision with the player actor, we are going to check if we can deal damage to the player, if that is true, we will deal damage, or in our case print something to the console hehehe

Leave a Reply

Your email address will not be published. Required fields are marked *