The game's developing a bit of a lonely feel. Just you, in space, wandering around uninhabited space mazes. Let's make things more interesting by adding enemies.
I've gone into a bit more detail than usual on this post. Also, if you're using a recent Chrome, Firefox or Safari, there are animated diagrams!
So. The first thing to think about is how the enemies should move. There are a few obvious patterns:
- Move up and down
- Move from side to side
- Go straight and turn when hitting a wall.
- Follow the left wall or the right wall.
- Follow the player.
- Move randomly.
For the patterns that involve turning left or right, we can define two versions of that enemy, a "left-handed" one which turns left and a "right-handed" one which turns right.
So, let's think about how to implement these enemies. What do they all have in common? Well, they all need to decide where to go next as soon as they enter a new square. The difference is in how each enemy makes that decision. Let's start with the simplest, the up-and-down enemy.
Here is a first-draft "decision function" for this enemy:
- If you can go forward, go forward.
- If not, turn around.
Looking at this, you can see that it would work not only for the up-and-down enemy but also the side-to-side one; the only difference is the initial direction. So, we can consider both these enemies to have the same movement pattern; let's call it the Oscillator.
If we use ↑ to mean "go forward" and ↓ to mean "turn around", we can summarize this enemy's movement pattern as ↑↓.
The next enemy type is also pretty straightforward:
- If you can go forward, go forward.
- If not, turn left or right.
We can define a left-handed and right-handed version of this enemy by changing which direction it turns in the second step. In fact, we can define a third version that choses randomly. Collectively, let's call these enemies Flyers, and summarize their movement patterns thus:
|↑↱↓ — Right-handed
|↑↰↓ — Left-handed
|↑? — Random
Now for the wall-followers. This isn't as obvious:
|↱↑↰↓ — Right-handed
|↰↑↱↓ — Left-handed
The obvious way to define a player-follower in this system would be to introduce a new command called "follow player" and have the player-follower's list consist only of that command.
We can do better, though. After all, it might be nice to be able to retreat from the player as well as follow them; or follow or avoid a different object, something other than the player.
With one small change, we can create enemies that behave like this using only the forward, backward and turn commands we've already defined.
First, we define a "relative axis" for each enemy type. All the enemies introduced so far have their relative axis pointing forwards, from their point of view. For the player-follower and the player-avoider, the relative axis points from it to the player.
Next, we interpret the results of the decision function differently: forward now means move in the direction of the relative axis; backward means go in the opposite direction, and left and right mean turn relative to the relative axis.
This way, the existing enemies' behaviour is unchanged, but we can define a player-follower with a decision function of ↑ and a player-avoider with ↓. We can also define enemies that follow or avoid any item we like. How about a moth-like enemy that's drawn to a light, or an enemy that's scared of other enemies?
It might be interesting to see how ↱ and ↰ behave in combination with the relative axis; perhaps it will yield some sort of orbiting behaviour?
Also, there may be other ways to play with the relative axis besides pointing it to some sort of target object.