Xenex Enemy AI Design Process


Enemy AI in and out of Combat Design Process

By Ryan Moore

When we were designing the combat style for Xenex, we took a lot of references from tactical turnbased games such as Baldurs Gate 3 and XCOM because we thought these games had perfected the style of combat we wanted to have for our game. While the player is in combat they will control their individual units by using a limited amount of action points to move their characters and perform attacks during their turn. The same goes for the enemies in our game and we want the enemies use the same type of combat as our players and sort of the same stats as the player units so the game will have some difficulty.

All of the enemies in our game will have two actions, an attack and a move, each of these will cost one action point to perform and what action will be used will be based on the distance from the closest player unit. We get which unit is closest to the enemy by putting all of the distances from each player unit in an array then checking which distance is the shortest by getting the min of the unit distances array.

Get Distance from Player Units Function


For the function above I used a for each loop to cycle through the array that carries each of the player units and checked their distance from the enemy that is performing their turn. This funtion is just to fill the Player Unit Distances array for later use when the enemy is deciding which player unit to attack or move closer to.

Deciding which player unit to attack



The images above show how I got the enemy to find the closest player unit and how I have the enemy decide which action to perform based on the distance from the closest player unit. I used an event for the enemy but I may have another way of calling this sequence when we find a way for the enemies to perform their actions one after another. First I call the funtion we previously made which gets the distances from each of the player units and fills an array with those values. After the array is filled, I then check which distance is the closest to the enemy by using a min of float array and use the index of the closest distance to get a reference to the closest player units location. To have the enemy decide which action to use I used a branch that checks if the closest player units distance is within attacking distance. If that is true the enemy will attack the player, clear the player unit distances array and decrease their action points by 1. If the closest player unit is not within attacking range the enemy will move towards the player a certain distance before losing an action point. 

How the enemy will move towards the player

Getting the enemy to move only a set distance towards the closest player without using the tick event was a bit trickey but, I have found a solution. If we use the distance from the closest player unit and the enemy whos performing their turn and subtract the max distance you want the enemy to move from it, we can use that value to #1 check if the closest player unit is farther than that max move distance, equal to or less than and #2 we can use that value to stop the enemy unit in a certain radius from the closest player unit. If the difference of those two values is less than or equal to zero the enemy can go right up to the closest player unit but, if the difference does not equal zero than the player unit is farther than the enemy units max distance. When the player unit it farther than that max distance we want the enemy unit to stop when move the max distance but still head towards the player. So to have both of these happen I have decided to use the AI Move To Acceptable radius input to stop the enemy from actually getting supper close to the player buy having that input equal the difference of the closest units distance and the max move distance. Once again after the enemy has reached either the player unit or moved their max distance the Player Unit Distances array will clear and an action point will be subtracted. This process is supposed to reset until the enemy is out of action points.

Enemy Attack



The enemy attack at the moment is set up a lot like the player unit attacks where they will be using a line trace by channel to decide whether or not they have hit an acceptable actor and if so apply a damage amount to that actor. This will be changed as development goes on to either shooting a projectile or having the player/enemy melee attack.

Enemy out of Combat

While the enemy is out of combat we wanted it to wander around the level and in the rooms they will be placed in. To do this, I used the event tick and the do once function so the enemy will only move to another area if they have reached their previous position and the enemy will find another location at a random time between 3 and 7 seconds. We also wanted the enemies to not wander the entire map but only in small areas so I gave them a radious of about 100 units in each direction from their current location. These values will probably change as we continue to work on this project.

What Still Needs to be Done

So far we have a bunch of basic things the enemy will be able to do such as move and attack but these actions and decisions have not yet been refined. We still need to have the enemy check for and exclude any dead player units when looking for the closest player unit, as they enter combat they need to imediatly stop moving, figure out different enemy attacks such as a ranged projectile or a mele attack and finally provide stats that will be used to determine damage inflicted, damage taken and accuracy of enemy attacks. This will be solidified and completed as the project progresses but I believe this is a very good basic funtionality templet that we will be useful in designing how our combat will work.

Get Xenex: Conscientious Culling

Leave a comment

Log in with itch.io to leave a comment.