Construct 2 RPG Series #5: Designing the Battle AI

In the last tutorial I made a (very) simple AI for enemies, even though the end result is just the enemy following the character around. Before I make the AI in much more complex code, I want to design it first. And even though this example is for enemy’s AI, the code can also be used to make an AI for our party member. AI for boss enemies will be the same, the only difference is in the value of parameters (or variables).

There’s gonna be a short range attacker and long range attacker in either enemies & player’s party member, there’s also gonna be a physical and magical attacker. So, based on the type, there are several types of fighting characters:

  • Close range physical attacker
  • long range physical attacker
  • Magical attacker
  • Healer / supportive

There is only one magical attacker because magicians can attack from close or far away, and it wouldn’t make much sense for a close range magical attacker, since he can be attacked while casting. Each physical attackers will have an attack radius that will differ between close range and long range attacker, attackers will move so that the target is in range before attacking. Magical attacker don’t need to move closer to the target, because the magic’s range is the entire battle field. But magics will have a casting time and magicians can be freely attacked while casting.

So how are we gonna make the AI? I’ll treat physical attacker’s AI differently than magical attacker’s AI. This is the logic process of physical attackers:

  1. If don’t have a target, look for enemies
  2. Move closer until target is in attack radius
  3. Attack target
  4. Decides whether defending or not
  5. If the enemy is still alive, back to no. 3
  6. If the enemy is dead, back to no. 1

That’s the rough design of the AI, these still need further designing. For example no. 3, when attacking the target will the attacker use normal attack or skills? And if I design the AI this way, I can make some customization to the AI (so the player can assign different AI to party members). I’ll discuss these 6 points as we go.

All attackers have an instance variables called radius, if there’s any target within this radius then the attacker will look for targets. To do this all battle participants have to know about the opposing party members (player party members know who are in enemy party members, and enemy party members know who are player party members). There are two ways to do this, one is to add instance variable to both party members which contains opposing party members, two is make a new family that can then be read by everyone in battle. Because both parties can read the data about their enemies at any time in battle, I’m gonna make two families that contain data about the member of enemy party and player party. This is more efficient than updating instance variable, for me.

There are few logics that we can use to determine the attacker’s target, such as:

  1. The closest to the attacker
  2. The farthest to the attacker
  3. The one with most current HP
  4. The one with the least current HP
  5. Always attack magicians first

Each attacker will have to remember their own logic of selecting their target, and for that reason we need one more instance variable for storing target selection logic. I will call this instance variable enemySelection and will store string values. To store target selection logic, these logics need to be represented in a string variable, like this:

  1. Closest enemy = “closest”
  2. Farthest enemy = “farthest”
  3. Enemy with most current HP = “strongest”
  4. Enemy with least current HP = “weakest”
  5. Attack magicians first = “mages”

this will make it easier for us when we write the code.

And then after we decide how the attacker select its target, the attacker will move closer to its target. Surely the attacker have to know which one is their target, and don’t change their target until the target dies. So we need another instance variable, we’re gonna name it targetName which contains the name of the target. But there’s a problem: what if there’s more than one kind of enemy in the enemy party? What if there are three yellow wolf in a battle scene? Which one will the other party member targets? To solve this we’re gonna give another instance variable in the enemy family called  battleName that contains string such as “yellowWolf1”, “yellowWolf2” and so on, the battleName’s value will be determined at the beginning of every battle.

The next step is to attack, this can be a normal attack or a skill. Each attacker will have a different percentage between a normal and skill attack, some will use normal attack more often others will use more skill based attacks. It’s just like the logic for choosing target, I will represent each logic with a string and store it in an instance variable, we’ll call it attackMethod. The logic for attacking are:

  1. Normal attacks only = “normal”
  2. Use a little skill based attacks = “few”
  3. Same probability of normal and skill attacks (50:50) = “balanced”
  4. Use more skill based attacks than normal attacks = “frontal”

Each attack logics have its own percentage between normal attacks: skill based attacks, which will determine the attacks. Of course, in case of skill based attacks, we will first check whether or not the attacker’s current SP is sufficient for the attack, or else it will be a normal attack.

The last step is to determine whether the attacker will defend or not. The enemy doesn’t actually have to enter defending state (so that the player can easily attack them), but I add defending probability to make some enemies more challenging. It will be the same as attacking logic, we’re gonna store the defending logic in an instance variable called defenseMethod. The defending logic names are:

  1. Not defending at all = “defenseless”
  2. Might be defending = “defensive”
  3. More chance of defending (50:50) = “defender”
  4. Almost always defending = “guardian”

If the attacker decides to defend, it will go into defending state for two seconds, before returning to the logic flows we made at the beginning.

Well, that’s all! I actually want to write about magicians AI as well, but this one post has been a long one, so I’m gonna write it next time.