DevLog: RPG Game Enemy AI

I have been looking for ways to show people what I am working with when it comes to programming in video games. Artists have their concept art and characters, level designers have their beautiful levels, but looking at a wall of code is just plain boring for anyone – well almost anyone.

In Computer Science they teach us that programming is defined as solving a problem. So to best illustrate my art in the form of problem solving and programming logic, I have decided to make developer logs. These logs should help shed some light on what goes on behind the scenes and in my brain when I’m programming. Normally, when you hear “Devlog” you think of the changes to a game. While that may be the case, I’ll be using it for something slightly different. However, yes, there will still be some walls of code – I just can’t help myself.

Today I begin my DevLog with a more recent experience: enemy artificial intelligence. In the game that I’m currently calling “RPG Game”, one feature will be combat similar to classic Final Fantasy: encounter an enemy, the screen transitions, then you battle the bad guys on the opposite side of the screen. In RPG Game, to make combat happen you must first encounter an enemy. In order to encounter an enemy, certain things have to be true about the enemy. For this game, I decided that I wanted to 1) have the enemies on the map- no random encounters, and 2) have those enemies feel like they have a mind of their own.

Wondering enemy. The sprite is placeholder.

The first thing I did was implement a MoveToPlayer method leveraging the Unity API’s Vector2.MoveTowards function. Using the current position of the enemy, the position of the player, and a set amount of time to move based on a constant. This method is called, and the enemy moves to the player when the player is within range of the enemy’s trigger collider:

I implement the battle screen pop-up when the enemy is within a pre-determined distance to the player.

The next thing that needed to happen was to give the enemy life; just standing around made the enemy seem not-so-nefarious. I created a few different tools and methods that helped accomplish this.

First, I started with an enum called FacingDirection with 4 states: Forward, Backward, Right, and Left:

If the player is not within the enemies attack range, then it begins to wander aimlessly. This is all done in my DetermineDestination function:

At the start of the game, a random direction is set using the FacingDirection enum. Inside of this function is a do loop that starts off selecting a random direction, but then checks to see if that direction is the current direction, recalculating if true in order to make the AI seen more real. This also helps to avoid the enemy from walking in a straight line forever. This random direction function is also used each time the DetermineDestination function is called:

After a FacingDirection is chosen, a random distance from the current location is chosen based on a minimum and maximum traveling distance that can be set to any enemy that has this script:

Finally, if the enemy either 1) reaches its destination or 2) hits a collider, the enemy stops, their sprite is updated to an idle sprite, they wait 2 seconds, a new destination is recalculated using the above logic, and finally movement is executed – in that precise order:

So the enemy’s base AI was created. After observing my specimen like a lab rat, I realized strange things were happening.

Problem: If a newly calculated route was adjacent to a collider the enemy just collided with, Unity’s OnCollisionEnter2D would not run the code it is supposed to (stop, recalculate, move). This is because the function is only meant to fire on enter, it doesn’t care about anything after that.

Solution: I also needed to know if I were currently inside a collider after the OnCollisionEnter2D did its work. I used Unity’s OnCollisionStay2D to always look for collision points and, if there were 3 or more points and the enemy was stopped, pass those points to an array. DetermineDestination will recalculate a point that is closer than the given colliders’ points found in the array:

Can you spot the refactoring opportunity?

And of course, while the enemy is moving, their sprite is updated. This is basic animation triggering so I won’t go into it for this DevLog.

At the end of the day, I’m happy with the way things are now in my enemy AI script. I will definitely need to refactor and make my code cleaner. I have been trying to stick to the concepts I have learned in school: self-documenting code, structured programming, and fixing bugs rather than patching them over with quick-fixes.

I am now at the point where I can comfortably move on to the combat phase of this game. My goal is to make the combat, character stat, and inventory systems as robust and complex as a Square Enix game, while attempting to keep the graphic design levels to a minimum, considering I am just a simple programmer after all.