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.
rows: defb $81,$00, $40,$80, $20,$40, $10,$20
defb $08,$10, $04,$08, $02,$04, $01,$02Before 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
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.
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.
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_rowA 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)