One meteor is enough to make a first dodge. We need a contact rule that is understandable, forgiving at the artwork’s edges, and independent of screen colours.
The ship stays at Y=160. We choose inset contact regions rather than testing every lit pixel. In this checkpoint a contact requires both:
- Meteor Y is at least 154 and less than 172.
- The absolute difference between meteor X and ship X is less than 16.
These numbers are game design choices. The visible images can nearly touch without a hit; their empty and decorative outer pixels do not all count as solid.
Source · view and edit
Companion file: assets.inc
The include line reads this editable data when you assemble. Keep it beside your source for a local build.
Edit the source, then assemble.
Edits are saved in this browser. Keep a downloaded copy of work you want to keep.
Focus the Spectrum screen to use the keyboard, or hold these buttons. Assemble again for a fresh machine.
Run the program to inspect it. Editing source does not change the running machine.
ship_x- —
meteor_x- —
meteor_y- —
phase- —
Stop before distance, predict the next instruction, then step. This pauses the actual CPU; it does not move an object into contact for you. RAM and registers show the paused state; the screen may show its last rendered frame.
Assemble before using the debugger.
Leave the ship still on the first run. Contact displays HIT and freezes movement. R retries. Steer away on the next run; when the meteor leaves, CLEAR SPACE confirms a near miss. Visual text supplies the outcome even with sound off.
Follow the horizontal decision
After moving the meteor and checking Y, the code subtracts ship X from meteor X. A subtraction can be negative. The carry branch distinguishes the case that needs neg, which replaces A with its negation. Either path reaches distance with the magnitude we want.
cp 16 compares without replacing A. A value below 16 continues into contact; a value of 16 or above branches to no_contact. This rule is symmetric: it works whichever side the ship occupies.
distance:
cp 16
jr nc,no_contact
call impact_sound
ld a,2
ld (phase),a
ld bc,$0201
ld de,hit_text
call textReassemble, then choose Stop at distance before the meteor hits. The debugger runs real instructions until that label, then pauses before CP. With the untouched starting position, A should be zero. Predict the branch result and step. AF shows A in its high byte and the flags in its low byte; the next instruction tells you which decision will run.
If the breakpoint is not reached, the run may already have ended or the meteor may have missed. Reassemble for the repeatable starting case. This debugger does not place objects into contact behind the scenes.
Test the edge, not just the centre
A meteor at X=116 misses a ship at X=100 or X=132: separation is exactly 16. At X=102 or X=130, separation is 14 and it hits. The native keyboard experiments exercise all four cases.
For an editable boundary experiment, change cp 16 at distance to cp 20. Run and compare near misses. You have changed the rule, not the artwork. Restore 16 before continuing.
Would changing the meteor's colour make it harmless?
Show the explanation
No. This code reads position bytes and compares numbers. It never reads bitmap or attribute memory to decide contact. You can redesign the picture without silently changing the collision rule.
The short impact_sound routine toggles the speaker output a bounded number of times. The speaker is bit 4 of port $FE: each pass writes 16 to set it and 0 to clear it, and a later unit turns this toggling into a proper tone. It is an event effect, not the game clock. Phase 2 freezes further movement; we do not add a recovery timer because one hit ends this game.
Sources
The maintained Meteor Storm source linked through this page supplies the game rules and data layout. Its experiments run original Z80 instructions on an emulated 48K PAL Spectrum; the game rules are design choices, not hardware properties.
Run it here
This unit's program, built for you.
- Program
- meteor-storm.tap
- Machine
- ZX Spectrum 48K (PAL)