On AI systems in top down games.
I’ve been doing some light work on a top down shooter game and simultaneously going through my first week at Flatiron school. We’re currently working through Object Relationships and I got hit with a bit of a lightning rod about how to work a problem with an AI system I was working on.
My goal for the system eventually is pretty simple to explain but difficult to implement. I want enemies that move a bit like a squad. They can flank the player, take cover, charge the player, cower in fear, run away. A number of squad based activities.
I think first it’s important to talk about the system I currently have in place and why I just hate it. It’s really the worst.

The above picture is a very barebones look at what the playing field might look like at any given moment. I am not an artist, I work in code please don’t judge me anymore than you already have.
The enemy has a number of States it exists in to start. Idle and chasing are the really relevant ones here. During the idle state the enemy checks how close it is to the player, if it’s within a certain distance (hereby the view_range) it checks if there is a straight line from it to the player and if that line is occluded by any objects. If not, it enters the chasing state.
In psuedo,
If Distance_to_Player < View_Range && Line_of_Sight is Unobstructed
Change State to Chase.
This is about as basic as AI gets. It’s also boring and predictable for the most part. You can add other things to spice this up, but for the most part those are dependent on movement speed, staggering, those sorts of mechanics. Many other great designers have made this work in the past but I am just a humble nobody so I’m not getting great results. I want my enemies to do things like take cover.
This is nothing new, but it’s an important part of making an enemy feel self serving and alive. I worked out a pretty basic implementation at one point that went something like this.

Every 30 frames or so (To save on computation) the player will shoot out some feelers (Represented in blue) until they hit a wall. That feeler will then keep going until it is no longer in a wall. Ta-da! you have now generated a bunch of locations an enemy can move to where they cannot be shot by a player. If you have the enemy move to the nearest cover-spot they can effectively take cover no problem. Our enemies now have a cover state. It works. Sort of.
See the problem is every enemy is still acting independently. I could, feasibly have every single enemy in the room alternating between firing at the player, and taking cover. The player has no chance, the game is unfair. I want some of the enemies to take pot shots at the player and most of them to hide in cover until forced out of it. This is where AI controllers come in.
I’m sure, for any seasoned game dev this concept has some far reaching scope and name and is about as old hat as they come, but for me it was a pretty eye opening concept, and is also where Object Relationships come in.
AI CONTROLLERS
I can have one AI controller for each squad of enemies that gets information about the player and chooses what each enemy will do based on the information.
So this controller needs some variables.
Minions: an array containing which enemies are being controlled by this controller.
Cover_spots: an array containing x and y coordinates of which spots are “in cover” at any given moment.
Max_life: A float containing the maximum HP of the entire enemy pool. This can be used as information to determine the general “mood” of the battle.
Current_life: A float containing how much HP is left in the entire enemy pool.
I’ll likely add more as this continues but this is a good start. I can use this for a number of different actions. Most importantly I can poll the status of each enemy and find out the percentage of them in certain states. Maybe no more than 2 percent of enemies can charge the player at any given time, or 5 percent of enemies are actively trying to flank the player at all times. I could even create classes of enemies that ignore the call from the controller and act on their own. Big scary brute enemies that still have access to all the controller information but are exempt from certain commands.
Here though we introduce the second system, room control.
ROOM CONTROL

Consider the room above. If you were to find an engaging place for enemies to go it wouldn’t be that hard. Place them in the area with the boxes and let them take pot shots at the enemy. If they need to flank the player they can simply follow the sides and get behind the player.
How do you make them decide to do that on their own? And what if the player moves? This is where room control comes in.

You can see a box in purple, this is key. This volume, hereby referred to as a zone, is active when the player is standing in it. You will also see a number of blue “c” markers on the map. These indicate cover spots that can be manually added to the map to increase control of the behavior of the enemies.
Each zone will contain some variables.
cover_spots: An Array containing each cover spot that is determined to be in cover from the perspective of that zone.
advantage: A int representing a rubric self determined by the map designer. It determines how likely the enemies are to “Press the advantage.” 0 being the least likely, 10 being most likely.
time_in_zone: An int that increments every frame the player is in the zone. The zone only becomes the “Active zone” when this increments to a certain number. This is to prevent AI confusion if the player is rapidly entering and leaving zones.
To interact with the player properly the player also needs a variable to determine how the zone effects the AI. Specifically the following.
n_of_zones_in_last_120_frames: This is a number that will decrement every 120 frames. If this number is larger than a certain threshold the zone the player is in will update to active. This is a fallback to the zone.time_in_zone in case the player is still causing odd behavior. Essentially the AI controller will “Chase” the player.
Now we could add other pieces to the zones to help the controller out, flank pathing, rush pathing, different “spots” for different enemy types to facilitate different attack styles. The list goes on, but for now I’m going to work through implementing the basic framework I have here.
Implementation
Now that we have our systems in place, how do they interact with each other?

Consider the poorly drawn opus above. One controller talks to many zones, and many enemies. The zones have relationships with many cover_spots, and the player. The player talks to one zone at a time, and the controller. The cover_spots have relationships with many zones, and many enemies. And finally the enemies get information with the controller, and have relationships with many cover spots. It’s a bit messy at the moment, but I promise I’ll expound from here.
Consider this scenario. The player has full health, full ammo and wanders into a room to fight a group of enemies. There are 30 enemies. The zone the player is standing in determines what cover spots the controller tells the enemies to move to. The enemies collaborate and make sure they are not moving to the same spot. The controller, knowing the player’s health and ammo are full, and knowing it has plenty of enemies, decides for a lightly aggressive approach. 5% percent of enemies, in this case 1.5 rounded up to 2, are told to charge the player. A further 10 percent, 3, enemies are told to stay close to cover, but fire on the player. This is a single interaction that is far more interesting than every enemy blindly chasing the player, and can be easily implemented in any number of levels. But how does the situation change as the interaction progresses?
The AI controller’s actions were successful and the player is down to 50 percent health and has expended much of their ammo attempting to take out the opponent. Meanwhile a stalwart 26 enemies remain. The computer knows it’s time to press the advantage. It determines that 50 percent of enemies should charge, the other 50 percent should hang back and be ready to swell the ranks. A staggering 13 enemies break cover all at once and charge the player. Very interesting.
The battle is beginning to change. The player has regained their full health, has whittled the advancing forces down and is faced with only 9 remaining enemies. The controller decides it’s time to flee. The enemies begin to move to cover spots furthest away from the player. As the player approaches they turn to face the player. Another unique and interesting reaction using the setup.
With this information and implementation a designer could, instead of focusing on small singular encounters with enemies, design levels to function as arenas for lively dynamic brawls with smart and surprising AI.
Coding and the Challenges.
Moving forward I am going to pseudo code a solution to this and begin to actual code this sucker sometime this week. I will, after achieving basic intended functionality, begin adding further features. Namely flank pathing, alternate enemy spots, and a secondary “Large enemy” controller that does much of the same thing but for larger more threatening enemies.
I’ll be prototyping the project in Game Maker studio, no offense to Ruby as a language, but I haven’t learned how to implement any sort of graphical element yet and probably shouldn’t skip too far ahead. Below is a video of my current, lackluster enemy AI. But don’t some of the graphics look pretty?