Okay, so that’s pretty simple but most games don’t use single-cell character graphics. What if the aliens are four character cells wide by two high, and the player’s character is three squares high by three wide? We need to check if any part of the alien has collided with any part of the player, so we need to check that the coordinates are within a certain range. If the alien is less than two squares above the player, or less than 3 below him then the vertical coordinates match. If the alien is also less than four squares to the left of the player, and less than three squares to the right then the horizontal position also matches and we have a collision.

Let’s write some code to do this. We can start by taking the player’s vertical coordinate:

ld a,(playx) ; player's x coordinate.

Then subtract the alien’s vertical position:

sub (ix+1) ; subtract alien x.

Next, subtract one from the player’s height, and add it.

add a,2 ; player is 3 high, so add 3 - 1 = 2.

If the alien is within range the result will be less than the combined height of the player and alien, so we perform the check:

Of course, this method doesn’t just work for character-based graphics, it works perfectly well with sprites too, but more of those later. It’s time to finish our game with some collision detection. As our graphics are all single-character UDGs we don’t need anything fancy, a quick x=x and y=y check are all we need.

But wait, why are there two tests for collision detection instead of one? Well, imagine the player’s gunbase is one character cell to the left of a centipede segment. The player is moving right and the segment is moving left. In the next frame the segment would move into the cell occupied by the player, and the player would move into the position occupied by the segment in the previous frame – player and centipede segment would move straight through each other and a single collision detection check would fail to pick this up. By checking for a collision after the player moves, and then again after the centipede segments have moved we can avoid the problem.

Collisions Between Sprites

Fair enough, most Spectrum games use sprites rather than UDGs so in the next chapter we shall see how sprites may be drawn. For collision detection, the same principle of coordinate checking can be used to detect collisions between sprites. Subtract the first sprite’s coordinates from those of the second, examine the difference and if it’s within the size range of the two sprites combined we have a collision on that axis. A simple collision check for two 16×16 pixel sprites might look something like this:

There is a drawback with this method. If your sprites don’t entirely fill their 16×16 pixel boundaries then the collision detection will appear to be too strict, and collisions will happen when sprites are close together but not actually touching. A slightly less sensitive check would involve clipping the corners of the sprites into a more octagonal shape, particularly if your sprites have rounded corners. The routine below works by adding the x and y coordinate differences and checking that they are below a certain limit. For a collision between two 16×16 sprites the maximum coordinate distances are 15 pixels for each axis, so by checking that the x and y differences are 25 or less we are effectively shaving a 5x5x5 pixel triangle from each corner.

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

Aliens Don’t Come One at a Time

Let us say, for the sake of example, we were writing a Space Invaders game featuring eleven columns, each containing five rows of invaders. It would be impractical to write the code for each of the fifty-five aliens in turn, so we need to set up a table. In Sinclair BASIC we might go about this by defining three arrays of fifty-five elements – one for the invaders’ x coordinates, one for y coordinates, plus a third status byte. We could do something similar in assembler by setting up three tables of fifty-five bytes each in memory, then adding the number for each alien to the start of each table to access the individual element. Unfortunately, that would be slow and cumbersome.

A far better method is to group the three data elements for each invader into a structure, and then have fifty-five of these structures in a table. We can then point hl to the address of each invader, and know that hl points to the status byte, hl plus one points to the x coordinate, and hl plus two points to the y coordinate. The code to display an alien might look something like this:

The drawback with this routine is that we have to be very careful where hl is pointing to all the time, so it might be an idea to store hl in a two-byte temporary memory location before calling show, then restoring it afterwards, adding three at the end of the main loop, then performing the djnz instruction. If we were writing for the Nintendo GameBoy with its cut-down Z80 this would probably represent our best option. On machines with more advanced processors such as the Spectrum and CPC464 we can use the index registers, ix, to simplify our code a little. Because the ix register pair allows us to displace our indirect addressing, we can point ix to the beginning of an alien’s data structure and access all elements within it without the need to change ix again. Using ix our alien display routine might look like this:

Using ix means we only ever need to point to the beginning of an alien’s data structure, so ix will always return the status for the current invader, ix+1 the x coordinate, and so on. This method enables the programmer to use complex data structures for his aliens of up to 128 bytes long, without getting confused as to which bit of the structure our registers are pointing at any given time as with the hl example earlier. Unfortunately, using ix is a little slower than hl, so we shouldn’t use it for the more intensive processing tasks such as manipulating graphics.

Let us apply this method to our Centipede game. Firstly, we need to decide how many segments are needed, and what data to store about each segment. In our game the segments will need to move left or right until they hit a mushroom, then move down and go back the other way. So it seems we will need a flag to indicate the particular direction a segment is travelling in, plus an x or y coordinate. Our flag can also be used to indicate that a particular segment has been destroyed. With this in mind we can set up a data structure of three bytes:

If we choose to have ten segments in our centipede, we need to reserve a table space of thirty bytes. Each segment needs to be initialised at the beginning, then deleted, moved and redisplayed during the game.

Initialising our segments is probably the simplest task, so we can use a simple loop incrementing the hl register pair for each byte before setting it. Something like this will usually do the trick:

Processing and displaying each segment is going to be slightly more complicated, so for that we will use the ix registers. We need to write a simple algorithm which manipulates a single segment left or right until it hits a mushroom, then moves down and switches direction. We’ll call this routine proseg (for “process segment”), and set up a loop which points to each segment in turn and calls proseg. Providing we get the movement algorithm correct we should then see a centipede snaking its way through the mushrooms. Applying this to our code is straightforward – we check the flag byte for each segment (ix) to see which way the segment is moving, increment or decrement the horizontal coordinate (ix+2) accordingly, then check the attribute at that character cell. If it’s green and black we increment the vertical coordinate (ix+1), and switch the direction flag (ix).

Okay, there are one or two other things to consider, such as hitting the sides or bottom of the screen, but that’s just a case of checking the segment’s coordinates and switching direction or moving to the top of the screen when we need to. The segments also need to be deleted from their old positions prior to being moved, the redisplayed at their new positions, but we have already covered the steps required to perform those tasks.

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

Finding Attributes

Anyone who ever spent time programming in Sinclair BASIC may well remember the ATTR function. This was a way to detect the colour attributes of any particular character cell on the screen, and though tricky for the BASIC programmer to grasp, could be very handy for simple collision detection. The method was so useful in fact that it its machine language equivalent was employed by a number of commercial games, and it is of great use to the novice Spectrum programmer.

There are two ways to find the colour attribute settings for a particular character cell on the Spectrum. A quick look through the Spectrum’s ROM disassembly reveals a routine at address 9603 which will do the job for us, or we can calculate the memory address ourselves.

The simplest way to find an attribute value is to use a couple of ROM routines:

However, it is much faster to do the calculation ourselves. It is also useful to calculate an attribute’s address, and not just its value, in case we want to write to it as well.

Calculating Attribute Addresses

Unlike the Spectrum’s awkward pixel layout, colour cells, located at addresses 22528 to 23295 inclusive, are arranged sequentially in RAM as one would expect. In other words, the screen’s top 32 attribute cells are located at addresses 22528 to 22559 going left to right, the second row of colour cells from 22560 to 22591 and so on. To find the address of a colour cell at print position (x,y) we therefore need only to multiply x by 32, add y, then add 22528 to the result. By then examining the contents of this address we can find out the colours displayed at a particular position, and act accordingly. The following example calculates the address of an attribute at character position (b,c) and returns it in the HL register pair.

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

Generating random numbers in machine code can be a tricky problem for a novice programmer.

First of all, let’s get one thing straight. There is no such thing as a random number generator. The CPU merely follows instructions and has no mind of its own, it cannot simply pluck a number out of thin air based on a whim. Instead, it needs to follow a formula which will produce an unpredictable sequence of numbers which do not appear to follow any sort of pattern, and therefore give the impression of randomness. All we can do is return a false – or pseudo – random number.

One method of obtaining a pseudo-random number would be to use the Fibonacci sequence, however the easiest and quickest method of generating a pseudo-random 8-bit number on the Spectrum is by stepping a pointer through the ROM, and examining the contents of the byte at each location in turn. There is one small drawback to this method – the Sinclair ROM contains a very uniform and non-random area towards the end which is best avoided. By limiting the pointer to, say, the first 8K of ROM we still have a sequence of 8192 “random” numbers, more than enough for most games. In fact, every game I have ever written with a random number generator uses this method, or a very similar one:

Let’s put our new random number generator to use in our Centipede game. Every Centipede game needs mushrooms – lots of them – scattered randomly across the play area, and we can now call the random routine to supply coordinates for each mushroom as we display them. The bits underlined are those we need to add.

Once run this listing looks more like a Centipede game than it did before, but there’s a major problem. The mushrooms are distributed in a random fashion around the screen, but the player can move straight through them. Some form of collision detection is required to prevent this happening, and we shall cover this in the next chapter.

Loudspeaker Sound Effects

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

The Loudspeaker

There are two ways of generating sound and music on the ZX Spectrum, the best and most complicated of which is via the AY38912 sound chip in the 128K models. This method is described in detail in a later chapter, but for now we will concern ourselves with the 48K loudspeaker. Simple it may be, but this method does have its uses especially for short sharp sound effects during games.

Beep

First of all we need to know how to produce a beep of a certain pitch and duration, and the Sinclair ROM has a fairly accessible routine to do the job for us at address 949, all that is required is to pass the parameters for pitch in the HL register pair and duration in DE, call 949 and we get an appropriate “beep”.

Alas, the way in which we work out the parameters required is a little tricky as it needs a little calculation. We need to know the Hertz value for the frequency of note to emit, essentially just the number of times the loudspeaker needs to be toggled each second to produce the desired pitch. A suitable table is located below (# stands for ‘sharp’):

Middle C 261.63

C# 277.18

D 293.66

D# 311.13

E 329.63

F 349.23

F# 369.99

G 392.00

G# 415.30

A 440.00

A# 466.16

B 493.88

For each octave higher, simply double the frequency, to go an octave lower halve it. For example, to produce a note C one octave higher than middle C we take the value for Middle C – 261.63, and double it to 523.26.

Once the frequency is established we multiply it by the number of seconds required and pass this to the ROM routine in the DE register pair as the duration – so to play the note at middle C for one tenth of a second the duration required would be 261.63 * 0.1 = 26. The pitch is worked out by first dividing the 437500 by the frequency, subtracting 30.125 and passing the result in the HL registers. For middle C this would mean a value of 437500 / 261.63 – 30.125 = 1642.

In other words:

DE = Duration = Frequency * Seconds

HL = Pitch = 437500 / Frequency – 30.125

So to play note G# one octave above that of middle C for one quarter of one second:

Have a play with the above routine – by fiddling with it it’s pretty easy to adjust the pitch up and down, and to change the starting frequency and pitch bend and length producing a number of interesting effects. One word of warning though – Don’t go too crazy with your pitch or duration values or the beeper routine will get stuck and you won’t be able to regain control of your Spectrum without resetting it.

White Noise

When using the loudspeaker we don’t even have to stick with the routines in the ROM, it is easy enough to write our own sound effects routines, especially if we want to generate white noise for crashes and bangs. White noise is usually a lot more fun to play with.

To generate white noise all we need is a quick and simple random number generator (a Fibonacci sequence might work, but I’d recommend stepping a pointer through the first 8K of ROM and fetching the byte at each location to get a reasonably random 8-bit number). Then write this value to port 254. Remember this port also controls the border colour so if you don’t want a striped multicolour border effect we need to mask off the border bits with AND 248 and add the number for the border colour we want (1 for blue, 2 for red etc.) before performing an OUT (254) instruction. When we’ve done this we need to put in a small delay loop (short for high pitch, long for lower pitch) and repeat the process a few hundred times. This will give us a nice “crash” effect.

This tutorial by Jon Kingsman (bigjon) originally appeared in a thread on WoSF. Reproduced with permission.

Roadrace game by bigjon, incorporating suggestions from Dr Beep, skoolkid and Matt B

Hi folks, I’m a machine code novice who coded a very small roadrace game to help me learn.

I reckon you can learn the basics of machine code in half an hour by coding this game step by step.

This tutorial assumes you have a working knowledge of ZX Spectrum basic, and the ZX Spin emulator.

Make yourself a large cup of tea – by the time you’ve drunk it, you be able to program in machine code!

CHAPTER 1 – Create a machine code function that returns the score to BASIC
Machine code programs are a series of bytes in the Spectrum’s memory.
In this chapter we will

– Use the Spin assembler to write a few bytes into the memory generating a score for our game.

– Write a BASIC program to run the machine code and print the score we have obtained from it.

Open ZX Spin. Select Tools -> Z80 Assembler.
To run our roadrace game, we need to execute the following steps:

MAIN ;label for main section of program as opposed to graphics data etc
;arrange to put our machine code at free, fast-running (over 32768) and memorable address in RAM
org 33000
;initialise score
;initialise road, car
PRINCIPALLOOP ;label for the loop in the game that will execute over and over
;read keyboard
;set new carposition
;crash? if so, go to GAMEOVER.
;print car
;scroll road
;random road left or right
;jump back to PRINCIPALLOOP
GAMEOVER ;label for the cleaning up that needs to be done before returning to BASIC
;return score to BASIC

Copy and paste the paragraph above into the Spin Assembler.It will appear as 15 lines of mainly grey text.

The text is grey because text after a ; is a comment. The assembler ignores it but it’s there for our benefit.

You can TAB comments over towards the right-hand side of the assembler page to make your code more readable.

The labels are in pink.The assembler won’t put anything in RAM for them but will use them as entry points to jump to.

In the assembler, do File -> Save as and type something like mc30mintut.asm into the save box.
We’ll do the first and last of these steps in this chapter, starting with the last one.

At the bottom window of the assembler you should see a report that says “No errors in 16 lines. 4 bytes generated”.

You can see the four bytes are now at memory address 33000 by clicking in the main Spin display window on Tools -> Debugger.

To run these four bytes of machine code, enter this one-line program in the main Spin display window: 10 PRINT AT 0,0; “Your score was “; USR 33000

Now RUN the program. Did you get “Your score was 0”? Congratulations – you have coded your first machine code program!

Do File -> Save in the main Spin display window and save as something like mc30mintut.sna. Here ends Chapter 1!

CHAPTER 2 – Display material on the screen.
There are two areas of the Spectrum’s memory which have a direct effect on the screen display.
The complicated way is the display file, from addresses 16384 to 22527, which stores a dash of 8 pixels per byte.

Try POKE-ing 255 into bytes within this range to see the funny order in which this memory area is mapped onto the screen.

The simple way is the attribute file, from 22528 to 23296, which affects an 8×8 pixel block per byte, in logical order.

In this chapter we will

Draw our ‘car’ by changing the paper colour of one character square to blue.

Draw our ‘road’ by using a loop to create two vertical stripes of black paper colour down the screen.

In the spin assembler line 5, delete the word ‘road’ in the comments.

At the beginning of line 5, type ld hl,23278. This points HL to the middle of the bottom row in the display file.

Insert line 6, ld a,8. This puts a blue PAPER colour into the A register. Why 8? See the BASIC manual chapter 16.

Insert line 7, ld (hl),a. The brackets round hl mean the load will be to the address in RAM that hl is pointing to.

Insert line 8, ld (32900),hl ;save car posn. We’ll store the attribute file address of the ‘car’ in some free bytes in RAM.

Now for the road. Insert line 4, ld hl,22537 ;initialise road. This points to a third of the way along the top line.

To save the road position, which we’ll need frequently, we’ll let the computer choose where to store it, on its ‘stack’.

Chapter 24 of the manual has a diagram showing where the machine stack is in the RAM.
To write to the stack we use push. To write from the stack we use pop. What goes on the stack first will come off last.

To print a black road we need 0 in the accumulator (ch16 of the BASIC manual).

We could do ld a, 0 but this takes 2 bytes whereas xor a takes only one. Insert line 6, xor a. xor compares the chosen register to the A register and puts a 1 in the A register for each bit that is different.

We’ll print the top line of the road. Two double squares of black with a 9-square gap between them.

Insert line 7, then copy and paste the following code:

ld (hl),a
inc hl ;inc increases the register by one, dec decreases it by one.
ld (hl),a
ld de,9 ;for a 9-space gap in the road.
add hl,de ;add adds the registers together, so hl points to the right hand side of the road.
ld (hl),a
inc hl
ld (hl),a

To get hl to point to the left hand verge on the next line, we need to move 21 bytes further in the attribute file.

Insert line 15, ld de, 21 ;point to left verge on next line
Insert line 16, add hl,de

To fill the screen with the road we will use machine code’s equivalent of a FOR-NEXT loop, djnz. djnz stands for Decrement then Jump if Not Zero. We load the b register with the number of times we want to loop.

Insert line 7, ld b,24 ;print road verge on 24 lines.
Insert line 8, fillscreen – this is the label for our loop to jump back to.
Insert line 19, djnz fillscreen.

Because our routine will continue from the loop when b=0, we no longer need to initialise b as well as c to 0 in the next line.

Change line 20 ld bc, 0 to ld c,b. This is one byte shorter.

Assemble and save. If you want to see the blue ‘car’, you’ll need to add something like 20 PAUSE 0 to your basic program.

CHAPTER 3 – move the car, test for collision.
Time to start playing the game! First we need to erase the car ready to move it if the player wants to.

Insert line 26, then copy and paste the following code:

ld hl,(32900) ;retrieve car posn
ld a,56 ;erase car
ld (hl),a

Before we read the keyboard we will lock the keyboard for most of the game, and unlock it only when we want to read the keys.

The instruction to lock the keyboard is di = ‘disable interrupts. Its opposite is ei = ‘enable interrupts’.