How To Write ZX Spectrum Games – Chapter 11

Enemy Movement

Note: This article was originally written by Jonathan Cauldwell and is reproduced here with permission.

So we have our playfield, and can allow the player to manipulate a sprite around it, but what we now need are some enemy sprites for the player to avoid. A new programmer could struggle here, but it really is far simpler than it first appears.

Patrolling Enemies

The easiest type of enemy to program is that with a fixed algorithm to follow, or a predetermined patrol route. We covered one such technique in the Centipede game earlier. Another very simple example is that found in games such as JetSet Willy, where a sprite travels in a single direction until it reaches the end of its patrol, then switches direction and heads back to its starting point, before changing direction again and starting the cycle again. As you might imagine, these routines are incredibly easy to write.

Firstly we set up our alien structure table with minimum and maximum coordinate positions and the present direction. It’s generally a good idea to comment these tables so we’ll do that too.

If we wanted to go further we might introduce an extra flag to our table, ix+6, to control the speed of the sprite, and only move it, say, every other frame if the flag is set. While simple to write and easy on memory usage, this sort of movement is rather basic and predictable and of limited use. For more complicated patrolling enemies, for example the alien attack waves in a shoot-em-up, we need tables of coordinates and while the code is again easy to write, coordinate tables quickly chew up memory especially if both x and y coordinates are stored. To access such a table we need two bytes per sprite which act as a pointer to the coordinate table.

The slightly more complicated example below demonstrates an 8-ship attack wave using a table of vertical coordinates. The horizontal position of each sprite moves left at a constant rate of 2 pixels per frame so there’s no need to bother storing it. It uses the shifter sprite routine from chapter 8 so the sprites are a little flickery, but that’s not important here.

So far we have dealt with predictable drones, but what if we want to give the player the illusion that enemy sprites are thinking for themselves? One way we could start to do this would be to give them an entirely random decision making process.

Here is the source code for Turbomania, a game originally written for the 1K coding competition in 2005. It’s very simple, but incorporates purely random movement. Enemy cars travel in a direction until they can no longer move, then select another direction at random. Additionally, a car may change direction at random even if it can continue in its present direction. It’s very primitive of course, just take a look at the mcar routine and you’ll see exactly what I mean.

If you have assembled this game and tried it out you will realise that it quickly becomes boring. It is very easy to stay out of the reach of enemy cars to cover one side of the track, then wait until the cars move and cover the other side. There is no hunter-killer aspect in this algorithm so the player is never chased down. What’s more, this routine is so simple cars will reverse direction without warning. In most games this is only acceptable if a sprite reaches a dead end and cannot move in any other direction.

Perhaps we should instead be writing routines where aliens interact with the player, and home in on him. Well, the most basic algorithm would be something along the lines of a basic x/y coordinate check, moving an alien sprite towards the player. The routine below shows how this might be achieved, the homing routine almov is the one which moves the chasing sprite around. Try guiding the number 1 block around the screen with keys ASD and F, and the number 2 block will follow you around the screen. However, in doing this we soon discover the basic flaw with this type of chase – it is very easy to trap the enemy sprite in a corner because the routine isn’t intelligent enough to move backwards in order to get around obstacles.

The best alien movement routines use a combination of random elements and hunter-killer algorithms. In order to overcome the problem in the listing above we need an extra flag to indicate the enemy’s present state or in this case its direction. We can move the sprite along in a certain direction until it becomes possible to switch course vertically or horizontally, whereupon a new direction is selected depending upon the player’s position. However, should it not be possible to move in the desired direction we go in the opposite direction instead. Using this method a sprite can find its own way around most mazes without getting stuck too often. In fact, to absolutely guarantee that the sprite will not get stuck we can add a random element so that every so often the new direction is chosen on a random basis rather than the difference in x and y coordinates.

Cranking up the Difficulty Levels

The weighting applied to the direction-changing decision will determine the sprite’s intelligence levels. If the new direction has a 90% chance of being chosen on a random basis and a 10% chance based on coordinates the alien will wander around aimlessly for a while and only home in on the player slowly. That said, a random decision can sometimes be the right one when chasing the player. An alien on a more difficult screen might have a 60% chance of choosing a new direction randomly, and a 40% chance of choosing the direction based on the player’s relative position. This alien will track the player a little more closely. By tweaking these percentage levels it is possible to determine difficulty levels throughout a game and ensure a smooth transition from the simplest of starting screens to fiendishly difficult final levels.