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:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
AI: { fires: "whenClose", movement: { scrolls: false, movesForward: true, stopsInFront: true, toPlayer: "toward" }, aiming: { follows: false, turnSpeed: "" } } |
The AI function of the entity is executed by the play state’s update function (once per frame). The function looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// Determine entity behavior var entityAI = function() { // Store the AI in a shorter variable var AI = this.preset.AI; // Determine forward movement if (AI.movement.scrolls) { // Make the entity scroll down the screen } else if (AI.movement.movesForward) { // Make entity move forward if (AI.movement.stopsInFront) { // Make entity stop moving forward when close to the player // And make it move back if it's past the player } // Determine lateral movement switch (AI.movement.toPlayer) { case "toward": // Make the entity move laterally toward the player break; case "away": // Make the entity move laterally away from the player break; default: // The entity stops moving laterally } } // Determine firing behavior switch (AI.fires) { case "always": // Make the entity shoot all the time break; case "whenClose": // Make the entity shoot when it's close to the player break; case "whenLinedUp": // Make the entity shoot when it's lined up with the player break; case "whenInFront": // Make the entity shoot when the player is in front of it break; default: // The entity doesn't shoot } } |
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:
- The entity moves laterally to line up with the player
- The entity moves forward
- 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.