## Sophisticated Movement

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

So far, we have moved sprites up, down, left and right by whole pixels.  However, many games require more sophisticated sprite manipulation.  Platform games require gravity, top-down racing games use rotational movement and others use inertia.

Jump and Inertia Tables

The simplest way of achieving gravity or inertia is to have a table of values.  For example, the Egghead games make use of a jump table and maintain a pointer to the current position.  Such a table might look like the one below.

```; Jump table.
; Values >128 are going up,```

With the pointer stored in jptr, we might do something like this:

```       ld hl,(jptr)        ; fetch jump pointer.
ld a,(hl)           ; next value.
cp 128              ; reached end of table?
jr nz,skip          ; no, we're okay.
dec hl              ; back to maximum velocity.
ld a,(hl)           ; fetch max speed.
skip   inc hl              ; move pointer along.
ld (jptr),hl        ; set next pointer position.
ld hl,verpos        ; player's vertical position.
ld (hl),a           ; set player's new position.```

To initiate a jump, we would set jptr to jtabu. To start falling, we would set it to jtabd.

Okay, so it’s a bit simplistic. In practice, we would usually use the value from the jump table as a loop counter, moving the player up or down one pixel at a time, checking for collisions with platforms, walls, deadly items etc as we go. We might also use the end marker (128) to signify that the player had fallen too far, and set a flag so that the next time the player hits something solid, he loses a life. That said, you get the picture.

Fractional Coordinates

If we want more sophisticated gravity, inertia, or rotational movement we need fractional coordinates. Up until now, with the Spectrum’s resolution at 256×192 pixels, we have only needed to use one byte per coordinate. If instead we use a two-byte register pair, the high byte for the integer and low byte for the fraction, we open up a whole new world of possibilities. This gives us 8 binary decimal places, allowing very precise and subtle movements. With a coordinate in the HL pair, we can set up the displacement in DE, and add the two together. When plotting our sprites, we simply use the high bytes as our x and y coordinates for our screen address calculation, and discard the low bytes which hold the fractions. The effect of adding a fraction to a coordinate will not be visible every frame, but even the smallest fraction, 1/256, will slowly move a sprite over time.

Now we can take a look at gravity. This is a constant force, in practice it accelerates an object towards the ground at 9.8m/s^2. To simulate it in a Spectrum game, we set up our vertical coordinate as a 16-bit word. We then set up a second 16-bit word for our momentum. Each frame, we add a tiny fraction to the momentum, then add the momentum to the vertical position. For example:

```       ld hl,(vermom)      ; momentum.
ld de,2             ; tiny fraction, 1/128.
ld (vermom),hl      ; store momentum.
ld de,(verpos)      ; vertical position.
ld (verpos),hl      ; store new position.
ret
verpos defw 0              ; vertical position.
vermom defw 0              ; vertical momentum.```

Then, to plot our sprites, we simply take the high byte of our vertical position, verpos+1, to give us the number of pixels from the top of the screen.  Different values of DE will vary the strength of the gravity, indeed we can even swap the direction by subtracting DE from HL, or by adding a negative distance (65536-distance).  We can apply the same to the y coordinate too, and have the sprite subject to momentum in all directions.  This is how we would go about writing a Thrust-style game.

Rotational Movement

The other thing we might need for a Thrust game, top-down racers, or anything where circles or basic trigonometry is involved is a sine/cosine table.  Mathematics isn’t everybody’s cup of tea, and if your trigonometry is a little rusty I suggest you read up on sines and cosines before continuing with the remainder of this chapter.

In mathematics, we can find the x and y distance from the centre of a circle given the radius and the angle by using sines and cosines.  However, whereas in maths a circle is made up of either 360 degrees or 2 PI radians, it is more convenient for the Spectrum programmer to represent his angle as, say, an 8-bit value from 0 to 255, or even use fewer bits, depending on the number of positions the player sprite can take.  He can then use this value to look up his 16-bit fractional values for the sine and cosine in a table.  Assuming we have an 8-bit angle set up in the accumulator, and we wish to find the sine, we simply access the table in a manner similar to this:

```       ld de,2             ; tiny fraction - 1/128.
ld l,a              ; angle in low byte.
ld h,0              ; zero displacement high byte.
add hl,hl           ; double displacement as entries are 16-bit.
ld de,sintab        ; address of sine table.