I have an obsession with making a compelling AI. An enemy entity that will patrol routes, react to sounds, look for you, detect you by sight, and hunt you down to eliminate you, while engaging tactically. Several years of developing Rushaug: Project Emerald has been dedicated to this. And this has been the largest quest of trial-and-error in my game making journey yet. This is by virtue of a single challenge; ID separation.
The enemies in Rushaug: Project Emerald are composed of several objects:
- A hitbox (Physical entity checking for collision with game terrain and other entities)
- Sensory object 1 (An object rendering a line between player and enemy to measure distance and visual obstruction)
- Sensory object 2 (An object monitoring slope depth in uneven terrain)
- Body sprite
- Front arm sprite
- Back arm sprite
- Tail sprite
This means the enemies need a solid parent-child system for the objects to interact with each other in a correct way. A parent-child system in itself is relatively easy to implement. This is applied for the player (Rushaug) as well, which is also composed of the same object structure. But the difference between the player and the enemies, is that the player is a singular entity. The enemies are plural entities, which makes it a more complicated matter. It is imperative that the game code is able to separate the correlative objects away from the rest of the objects. Otherwise, we could get a scenario where an enemy sees Rushaug, and in response; an enemy on the other side of the map starts shooting toward Rushaug without any cue. Another scenario could be that Rushaug shoots one enemy, making every other enemy in the level all die at once.
This is tackled with an ID system, which separates identical objects from each other with unique ID’s, and makes in-game circumstances take identity into consideration. Implementing an ID system is also a relatively easy feat, but when you combine ID separation with a parent-child system, you start to get some complicated issues. Combining ID separation with a parent-child object orientation has been the most challenging task in my programming career thus far.
There are game making tools which handles this automatically, but the framework which I am building my game on, does not exploit this. Even if it did, I might not have utilized it anyway. I am obsessed with programming game systems from the ground up, to have total control of how the game code works. This works to my advantage, making it possible to tweak the tiniest bits for any purpose. But it doesn’t come absent challenge. It has definitely been a learning experience.
September of 2016, I had an eureka moment where I finally solved my ID issue, and on play-testing, I witnessed my enemies move around individually, reacting to conditions under their own circumstances. It is by far one of the most satisfying moments in my time developing Rushaug: Project Emerald.
It was at this point it was time to move on onto my second challenge; Programming the enemies’ behavior.
This is far easier than our last task, but does take a lot of time and consideration. When you program an AI, you have to conceptualize hundreds of detailed circumstances that can potentially happen in-game, and follow up by stating how the AI will respond to those circumstances. The complexity of this step can vary greatly based on how advanced you want your enemy AI to be. It could potentially be as uncomplicated as this;
IF enemy sees player THEN enemy fires at player
Easy, right? But if you want a more complex AI that takes a lot of components into consideration, it will be more like this;
IF enemy hears player, enemy mode is patrolling THEN enemy mode change to alert
IF enemy hears player, enemy mode is alert THEN enemy looks in direction of player
IF enemy sees player, enemy is >500px away player THEN enemy moves toward player
IF enemy sees player, enemy is <500px near player THEN enemy activate alarm
IF enemy sees player, enemy is <500px near player, alarm is active THEN enemy fires at player
This is simplifying it, but the principle does come across. Programming behaviors can be tedious, but at the same time fun to experiment with how the AI interacts with the game world and how it reacts to certain conditions; such as an empty elevator arriving at the same floor as the enemy. The enemy could for example react by investigating the elevator, and ride it to the floor it came from.
At this point in development, the AI is competent and challenging to the player. Enemies will patrol routes, stand guard, and actively search for the player. They will react to sounds, prepare for engagement when the alarm is triggered, and fire a stream of bullets towards the player if he or she wanders into their line of sight. If the player hides behind a crate to avoid gunfire, the enemy won’t spare any time to regain composure. They will seize fire, push forward, and jump the player, if he or she does not return fire.
You better stay sharp!