Episode 12: AI

In addition to building entities, the entity factory also sets the AI (artificial intelligence) of said entities.

I have to admit that I knew nothing about AI programming heading into this, and by the end of it I still didn’t know anything, but I did have a working AI system!

The way I implemented AI was to simply write functions for each type of entity that checks the AI settings in its preset to see how it should behave. Here’s an example of the AI settings of an enemy:

The AI function of the entity is executed by the play state’s update function (once per frame). The function looks like this:

Using nested conditionals and switch statements usually isn’t a good way to do anything, but it was the most obvious solution. Plus the behavior is pretty basic, so I didn’t want to waste too much time on it.

Here’s how the preset at the top of the page would end up working:

  1. The entity moves laterally to line up with the player
  2. The entity moves forward
  3. Once the entity is close to the player, it stops moving forward and starts firing

Pretty neat, huh?

The obstacles and drops just scroll across the screen, but the enemy AI seems to work pretty well. I added a few more features, like having enemies try to use their modules or turn toward (or away from) the player.

I’m also pondering whether or not to have enemies use their secondary weapons. Enemies are vessels, and vessels have both sets of weapons, but how would they decide what set to use? I guess they could alternate between the two, but what would determine when to alternate? So many questions.

Episode 9: Entities

In order to have a proper shooter, we need stuff to shoot. Enter entities.

Entities, as I chose to call them, are the things in the game that interact with one another. In Zyrian there are four types of entities:

  • Player: the thing that the player controls
  • Enemy: things that are trying to destroy the player
  • Obstacle: things that the player can crash into
  • Drop: things the player can pick up

All these entities can be requested from the entity factory in much the same way we would get an item from the item factory…

And just like requesting an item, we can randomize anything we want by omitting a parameter. If the entity has items, as we’ll see they can, then the function will request them from the item factory.

Vessels

The first problem I encountered when designing my entities was how the entity objects relate to each other.  I wanted to figure out what they had in common with each other, so that I could use inheritance to increase code reuse and allow for expansion. For semantic reasons, this ended up being a little harder than I thought.

Players and enemies are both pretty similar – they’re ships that fly around the screen. But wait, if players and entities are ships, and if ships are items (as we saw in the last episode), then players and enemies are items.

On top of that, if items belong to ships, and if ships are items, then items can belong to items, which doesn’t really make sense.

The problem here is the use of the term ship to refer to both a type of entity and a type of item. What we need is a new term to describe an entity that has a ship and other items. Enter vessels.

Vessels are sprites with items, and one of those items is a ship. This makes things a little easier to understand, and it allows the entity to change its ship without disrupting the other items. This may not be the best solution, but I thought it made sense.

The Player

The player’s vessel is made up of the items that the player owns (I’ll talk about I saved the player’s data in another episode). So when we request a player entity (which is a vessel) from the entity factory, it looks at the items that belong to the player, fetches them from the item factory, attaches them to a vessel, and returns the vessel.

Enemies

The way an enemy’s vessel is constructed is a little different. Entities, like items, have types and presets defined in a JSON file that I called entities.json.

This file specifies the different items that an entity has. It also defines some multipliers to make enemies have more life and deal less damage than the player. Without them, the player would be evenly matched with each enemy, which probably wouldn’t be fun.

There were four basic kinds of enemy presets that I came up with:

  • Enemies that fly past the player and don’t shoot
  • Enemies that move toward the player and shoot
  • Enemies that stay at the back of the screen and shoot
  • Enemies that don’t move, but can rotate and fire at the player

Turrets

The fourth type of enemy is referred to as a turret in the game, but this entity type doesn’t actually exist in code. Turrets are just vessels that have special ships and AI and can’t move. They simply scroll past the player like an obstacle or drop, fire their weapons, and some of them aim at the player.

In order to prevent the player from acquiring the ships that turrets use, I added the unpurchasable attribute to those ship items. This prevents vendors and drops from spawning items we don’t want the player to obtain.

Obstacles

Unlike the player and the enemies, obstacles don’t have items. Obstacles are just sprites with some stats added to them based on the preset, level, faction, and rarity. The stats are:

  • Health
  • Crash damage
  • Invincible

Obstacles don’t really do anything other than float across the screen and deal damage to the player when they collide. They mainly exist to add shape and variety to missions. Anyway, here’s how I make ’em:

For my obstacle presets I just chose a bunch of sprites with different sizes and shapes.

Drops

Drops are what the player picks up during a mission. They don’t have items, and they don’t deal damage. They’re basically just sprites with the following stats:

  • Reward type
  • Rarity

The reward can either be an item or some money (more on currency in the episode on factions), and it’s modified by the rarity. So a legendary drop could either contain money multiplied by the legendary rarity’s money multiplier, or it could contain a legendary item. The drop’s preset would determine either the base amount of money or the item reward.

The drop presets are just a few options with different amounts of money and then a one that gives a random item. Here’s how I get one:

So those are my entities. In the next episodes I’ll talk about how they are generated during gameplay and how their behavior is controlled.