Creating Enemies And Their AI (November 2017)

In the previous blog post of this series (The Beginnings), I discussed the foundations of the game. These were things like the story, movement mechanics, sprite design, and lifeform stats. In this blog post, I will be discussing creating the very first enemies and the early version of their AI.

Enemies And AI

To implement AI, all lifeforms would function as a concept called finite state machines - which is the idea that a lifeform is only ever doing one thing at a time. 

Whatever thing the lifeform is doing is called a state. Essentially, a lifeform is only ever in one state at a time. States are everything that make up the lifeform's decision-making process and actions. For example, standing still is a state (idle state). Moving from point A to B is another state (moving state). A jump is made up of three states: jump-in (going from being on the ground to in the air), jump-idle (repeating this state until an obstacle is hit), and jump-finish (landing on the ground).

With all this in mind, I drafted up the initial versions of AI. 

The Feel Of AI

To me, the feel of the AI, is one of the most significant parts of designing my game. I wanted the enemies to feel smart. Somehow, in some way, I wanted there to be a "wow" factor when engaging in combat. The way I achieved this was by introducing small amounts of randomness to nearly every decision path an enemy could take to achieve their desired action. 

From what I can remember, my overall philosophy and way to create enemies has not changed since I first created their framework. When an enemy spawns, it is assigned aggression probabilities, which create its personality. Certain enemies may be very eager to always attack. Others may like to anticipate player actions first (i.e., block a player attack before responding). Some may like to chain their attacks together (i.e., a sword swings once and transitions into a second swing). Maybe they have a preferred long-range attack and often dodge the player to get into that ideal range for their favorite attack. Overall, there are a variety of possible ways to craft an enemy's personality.

For any enemy to acquire a target, I had to establish a repeatable process that would allow it to constantly engage its desired target. At a high level, I came up with the following:
  1. Search for the player (idle state, movement state)
  2. Upon finding a target, calculate if close enough and what action to do next
  3. Get close enough to take action (chase state)
  4. When in range, switch to the action (attack state, block state, dodge state, etc)
  5. Upon completion of step 4, repeat step 1
With these ideas in mind, the first results of creating the AI personalities were not pretty. State changes were immediate with no indication of transition. Sometimes there would be a delay between actions. The same attack style could be chosen repeatedly, which was the opposite of appearing random. The sentient feeling had not been produced yet - the AI was too choppy and aggressive. But I could recognize that, with enough improvements, there was potential for it to grow into something truly polished.

November 3rd, 2017
In general, what happens when you create a large enough range of personalities, is that the player is uncertain of how the outcome of their first engagement with a new enemy will turn out. This is essential. It keeps the player on edge - always thinking and preparing for different scenarios. 

However, there is a fine balance that must be achieved when implementing concepts like this. The player must win some encounters, and must lose some encounters. The player needs to lose enough encounters to properly improve their skillset, battle-preparation, and ingame knowledge (of enemy potential capability). It can be a firm reminder that they chose to play a challenging game and that in some scenarios, they simply are not the best. It creates a risk versus reward environment. Whereas the reward is not always necessarily good loot or experience (for leveling up stats). The reward comes in a greater form: the player feels like their practice and skills have reached a point where it allows them to best a hard challenge. The player will leave the experience behind with the feeling that they had truly accomplished something.

In the beginning of development, I was mostly implementing things as the need occurred. So, after I got the feel of the AI to a point I liked, I created a new look for the player. This was the result:

November 12th, 2017
The idea was inspired from a variety of different games and armor designs. I really enjoyed this model design. My animation skills were not the greatest, so the movement looked very awkward. Using the new skin, I created a variation for an enemy that was all white. 

Now, let's get back to the feel of the AI. Another important part of making sure the AI felt intelligent was implementing the ability of two enemies to fight each other. As I mentioned earlier, essentially every creature is viewed as a lifeform (player and enemy alike). Implementing this part of the AI ended up being easy. The enemy's target was no longer only a player but now another enemy. However, in the eyes of the AI, it was the same thing - just another lifeform target.

November 12th, 2017
Over time, as the game developed and I improved the AI, it became something I was very proud of. I think that the current AI is one of the best components of my game.

Enemy Target Priority

Now that I was introducing the concept of an enemy fighting something other than the player, this meant it was possible for an enemy to acquire multiple targets at once. The enemy could no longer only rely on single-priority target locking. It would be too easy to exploit.

For example, suppose an enemy has two possible targets: player and player's follower (some sort of companion). Consider two scenarios:
  1. The enemy locks onto the player because it is closest. The player kites the enemy during combat. This means that the player always stays just outside the enemy's attack range, forcing the enemy to constantly chase the player. Meanwhile, the player's follower does all the damage. 
  2. The enemy locks onto the player's follower because it is closest. The player's follower can absorb all enemy damage, while the player deals out damage.
In both of these scenarios, the enemy is not actually identifying its most serious threat. Instead, it is a clear exploitation of poorly designed combat targeting.

The solution is to introduce a system where the enemy remembers how much damage a target has done. Then, have the enemy run through its acquisition process again with a slight modification after each combat action. So, if an enemy swings their sword, then they subsequently scan the area for a possible better target. 

Now, with the enemy remembering what has dealt damage, target acquisition begins by going through all previous targets that have dealt damage to the enemy. Starting at whatever target has dealt the greatest amount of damage, it checks to see if that target can be reached. If yes, then that becomes the new target, and the enemy will engage.

With this new concept in mind, redoing the two scenarios from earlier produces ideal results:
  1. As the player's follower deals more damage than the player, the enemy will instead target the player's follower (successfully ignoring the kiting).
  2. As the player deals more damage than the player's follower, the enemy will instead target the player.

The UI (User Interface) And First Level

With combat working to my approved standards, it was time to implement the ingame UI. My intention was to allow the player to modify their stats and change equipment. Then, after completing the UI, I could work on creating the first level of the game. I will discuss these things in the next blog post.

Thank you for reading.

    

Comments

Popular posts from this blog

The Beginnings (July - November, 2017)

Looking for an artist to join our team!