Skip to content

Prepare eight horizontal positions

  • Sinclair ZX Spectrum
  • Assembly

We can move a row one pixel by shifting it. To draw a moving ship repeatedly, we will prepare the possible offsets once and select the one we need.

Keep the same sixteen-pixel pair from the previous lesson. Shift it by zero, one, two and up to seven places. Eight offsets cover every position inside a byte; the next position starts a new byte column.

Make a table before using one

Replace the previous program with this complete checkpoint. rows contains eight pairs, each made by shifting $8100 right by the row number. defb stores those byte values; it does not execute a drawing instruction.

meteor-storm.asm, excerpt
rows: defb $81,$00, $40,$80, $20,$40, $10,$20
      defb $08,$10, $04,$08, $02,$04, $01,$02

Before running, calculate the last pair. The original leftmost pixel moves to the last bit of the first byte; the original rightmost pixel moves to the next-to-last bit of the second. That gives $01,$02.

Source · view and edit
ZX Spectrum

Edit the source, then assemble.

Edits are saved in this browser. Keep a downloaded copy of work you want to keep.

Run the program to inspect it. Editing source does not change the running machine.

The two bitmap bytes on each row, read from RAM. White is a set bit; black is a cleared bit.
Run to read the bytes.

Read a pair, then move down

HL points into rows. DE points into screen memory, initially $480C. The loop copies the first byte, increments both pointers, then copies the second. dec e returns to the original screen column. inc d selects the next scanline in this eight-row group. B counts eight rows; djnz decrements it and repeats while it is nonzero.

That address shortcut works for this one group. It is not a general way to move down the Spectrum screen: crossing from the eighth scanline to the next group needs different address changes. The next experiment tackles the general layout.

meteor-storm.asm, excerpt
copy_row:
 ld a,(hl)
 ld (de),a
 inc hl
 inc e
 ld a,(hl)
 ld (de),a
 inc hl
 dec e
 inc d
 djnz copy_row

A table is a trade-off

Drawing can now look up bytes rather than shift each image while the game runs. We spend memory to save repeated work. The final ship has sixteen rows, four bytes per stored row and eight offsets: 16 × 4 × 8 = 512 bytes. Unshifted artwork alone would need only 16 × 3 = 48 bytes.

Why four stored bytes for artwork that is three bytes wide? Shifting can spill pixels into a fourth byte, just as our one-byte pattern spills into a second. We keep every stored row the same size so the next row is easy to locate.

If the ship moves from x=15 to x=16, do we need a ninth shifted copy?

Show the explanation

No. At x=15 the byte column is 1 and the offset is 7. At x=16 the byte column is 2 and the offset returns to 0. The same eight copies work across the screen.

Change only the final pair to $00,$00, run again, and explain which row disappears. This is an asset edit: the copying instructions still work. Restore it before continuing. Later, a host-side Python script prepares the larger tables from our original artwork; it applies the same shift you have just checked by hand.

Sources

Sinclair Research, ZX Spectrum BASIC Programming, chapter 24, display-file and attribute layout. Zilog, Z80 CPU User Manual, UM008011-0816, instruction descriptions for shifts, logical operations and loads.

Run it here

This unit's program, built for you.

Program
meteor-storm.tap
Machine
ZX Spectrum 48K (PAL)

Download meteor-storm.tap