Crasher

Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game

This is an arcade-style dodging game where the player moves a car left and right across the bottom of the screen to avoid rapidly changing road conditions. The program defines three custom UDG characters (UDGs “a”, “b”, and “c”) via POKE into USR addresses, using DATA blocks containing pixel patterns. Collision detection is performed using SCREEN$ and ATTR checks at line 120 and 155 rather than coordinate arithmetic, a common Spectrum BASIC technique. The title screen loops with a randomized border color effect via OUT 254 and plays continuous BEEP tones while waiting for a keypress on keys “5” or “8”. A high-score melody is stored as NOTE/DURATION pairs in DATA statements starting at line 9040 and replayed via BEEP in a READ loop.


Program Analysis

Program Structure

The program is organized into several functional regions:

  1. Lines 1–10: Initialization — calls UDG setup subroutine at 8010, dimensions the screen buffer string i$ (704 chars = 22 rows × 32 cols), sets high score h=100, jumps to the attract loop.
  2. Lines 20–160: Main game loop — resets score and positions, cycles through 11 scoring rounds (FOR s=0 TO 10), moves the falling object, reads player input, checks for collision.
  3. Lines 200–243: End-of-round and attract screen — shows score, plays death tune, branches to high-score routine if appropriate, redisplays title and waits for “5” (play) or “8” (toggle noise).
  4. Lines 245–249: Noise-off wait state — waits for “5” to play or “8” to resume noise loop.
  5. Lines 500–550: High-score celebration — prints congratulatory message, plays a tune from DATA, updates h.
  6. Lines 8010–8070: UDG loader — pokes pixel data into UDG addresses for characters “a”, “b”, “c”.
  7. Lines 9040–9080: Music DATA for high-score tune (note, duration pairs).
  8. Lines 9500–9510: Screen-clear subroutine — uses i$ to OVER 1 print 704 spaces, then CLS, resetting attributes cleanly.
  9. Line 9998: SAVE with auto-run.

UDG Character Definitions

Lines 8010–8070 define three UDGs by reading DATA bytes and POKEing them into memory starting at USR "a" through USR "c"+7. The loop iterates over all 24 bytes (3 UDGs × 8 bytes each).

UDGData (hex approx.)Role
\a (UDG “a”)0,62,8,62,28,62,28,0Falling ball/object
\b (UDG “b”)255,170,213,170,213,170,213,255Left half of paddle
\c (UDG “c”)255,171,85,171,85,171,85,171,255 (9 bytes — see anomaly)Right half of paddle

Note: the DATA block for UDG “c” at line 8060 contains nine values rather than eight. The loop runs from USR "a" to USR "c"+7, which is exactly 24 iterations, so the ninth value (171) is read but never POKEd — it is effectively ignored. This is a minor data anomaly but causes no runtime error.

Game Mechanics

The falling object’s column c starts at 12 and is fixed; its row r is updated each iteration with a random walk: r decrements if rnd=1 and r>1, or increments if rnd=0 and r<20. This produces a side-to-side drift rather than a downward fall — the variable names r (row) and c (column) are used in a somewhat reversed sense from convention.

Player input is read at line 110: keys “5” (left) and “8” (right) move the catcher column c. The program also polls PEEK 23560 (the last key pressed system variable) to detect key 9 (ASCII 57) as a repeat-prevention guard, then resets it to 54 (key “6”) at line 115 — an unusual choice for debouncing.

Collision Detection

Two checks are used in sequence:

  • Line 120: SCREEN$ (16,c) — if the cell at the car’s screen position is not a space, a collision is flagged and the game jumps to line 200 (game over). A non-space result means the paddle is under the ball.
  • Line 155: ATTR (16,c) — checks the attribute byte; value 122 corresponds to BRIGHT 1, PAPER 4, INK 2 (the wall’s color scheme). If the attribute doesn’t match, the car crashed and the game ends.

Using both SCREEN$ and ATTR together provides a more robust test than either alone, though in practice the SCREEN$ check at line 120 will catch most misses before line 155 is reached.

Screen-Clear Subroutine (Line 9500)

Rather than simply calling CLS, this subroutine PRINTs the 704-character string i$ (initialized as spaces by DIM) with OVER 1 at position 0,0, effectively XORing the existing screen contents before clearing. This technique removes any lingering INK/PAPER attribute color bleed that a plain CLS might leave in certain display states. It also resets POKE 23624,0 (the scroll counter).

Attract Screen and Sound Loop

The attract loop at lines 240–249 plays a sweeping BEEP tone (notes 3 to 6, step 0.5) while randomly changing the border color via OUT 254, INT(RND*7). Two states are implemented: noise-on (line 240 loop) and noise-off (lines 247–249 wait loop), toggled by pressing “8”. Pressing “5” at any point jumps to line 20 to start the game.

High-Score Routine

The high-score subroutine (lines 500–550) plays a 15-note melody stored as interleaved NOTE, DURATION pairs in DATA lines 9040–9080. The READ loop at line 540 uses a slightly unusual construction: IF INKEY$="" THEN NEXT n: GO TO 510 — note that line 510 does not exist, which causes the program to fall through to the next available line (line 530 area). This is a deliberate GO TO non-existent line technique to restart the display portion without re-entering the subroutine fully. However, there is a potential issue: RESTORE 9040 is called each time, and the loop variable n is reused, which could interact with the outer game loop’s use of n in some edge cases.

Notable BASIC Idioms

  • Boolean arithmetic for movement: r=r-(rnd=1 AND r>1)+(rnd=0 AND r<20) uses the Spectrum’s TRUE=1/FALSE=0 convention to avoid IF statements.
  • Similarly, c=c+(INKEY$="8")-(INKEY$="5") moves the paddle in one expression.
  • POKE 23692,12 sets the scroll count to suppress the “scroll?” prompt during the game loop.
  • The title screen text at line 235 uses block graphic escape sequences to render a decorative logo banner.

Content

Related Products

Related Articles

Related Content

Image Gallery

Crasher

Source Code

    1 GO SUB 8010
   10 DIM i$(704): LET h=100: GO TO 230
   20 GO SUB 9500
   30 LET sc=0: LET r=10: LET c=12
   40 POKE 23692,12
   50 FOR s=0 TO 10
   60 LET rnd=INT (RND*2)
   70 LET r=r-(rnd=1 AND r>1)+(rnd=0 AND r<20)
   80 PRINT AT 16,c; BRIGHT (sc>4); PAPER 7; INK 2;"\a"
   90 PRINT AT 21,r; BRIGHT 1; INK 2; PAPER 4;"\b\c"; PAPER 7;TAB r+6; PAPER 4;"\b\c"
  100 PRINT 
  110 LET c=c+(INKEY$="8")-(INKEY$="5"): IF PEEK 23560=57 THEN GO TO 110
  115 POKE 23560,54
  120 IF SCREEN$ (16,c)<>" " THEN GO TO 200
  130 LET sc=sc+1
  140 BEEP .005,s
  150 NEXT s
  155 IF ATTR (16,c)<>122 THEN GO TO 200
  160 GO TO 40
  200 PRINT AT 16,c; FLASH 1; INK 0; PAPER 4;"\a"
  205 PRINT AT 10,10; INK 6; PAPER 2; FLASH 1;"You scored ";sc;AT 12,9;"High score:";h
  210 FOR n=10 TO 40 STEP .4: BEEP .001,n: NEXT n
  220 IF sc>h THEN GO SUB 500
  230 GO SUB 9500: PRINT AT 13,0; FLASH 1; INK 5; PAPER 1;"     Press '5' to play or '8' to                                  stop/re-start noise.Use '5' & '8' to move left or right          ";AT 1,10;"High score:";h
  235 PRINT AT 5,0; INK 2; PAPER 5;"      \:'\'' \:'\': \:'\': \:'\'' \: \ : \:'\'' \:'\':            \:   \:'\:' \:'\': \''\': \:'\': \:'\'' \:'\:'            \''\'' \' \'' \' \ ' \''\'' \' \ ' \''\'' \' \''      "           
  240 POKE 23560,0: FOR n=3 TO 6 STEP .5: BEEP .007,n: OUT 254,INT (RND*7): NEXT n
  241 IF PEEK 23560=56 THEN PAUSE 0: GO TO 245
  242 IF PEEK 23560=53 THEN GO TO 20
  243 GO TO 240
  245 POKE 23560,0
  247 IF PEEK 23560=53 THEN GO TO 20
  248 IF PEEK 23560=56 THEN GO TO 240
  249 GO TO 247
  500 GO SUB 9500: PRINT AT 10,1; FLASH 1; PAPER 2; INK 4;"         A high score!        "
  530 PRINT AT 12,5; PAPER 5; INK 3; FLASH 1;"The high score was:";h;AT 14,5;"The high score is :";sc;AT 16,10;"Press a key"
  540 RESTORE 9040: FOR n=1 TO 15: READ z: READ x: BEEP x,z: IF INKEY$="" THEN NEXT n: GO TO 510
  550 LET h=sc: RETURN 
 8010 FOR n=USR "a" TO USR "c"+7
 8020 READ a: POKE n,a
 8030 NEXT n
 8040 DATA 0,62,8,62,28,62,28,0
 8050 DATA 255,170,213,170,213,170,213,255
 8060 DATA 255,171,85,171,85,171,85,171,255
 8070 RETURN 
 9040 DATA 0,.3,0,.2,5,1.25
 9050 DATA 0,.3,5,.18,9,1.25
 9060 DATA 0,.3,5,.18,9,.4
 9070 DATA 0,.3,5,.18,9,.4
 9080 DATA 0,.3,5,.18,9,1.5
 9500 FLASH 0: BRIGHT 1: PAPER 7: INK 1: BORDER 0: PRINT AT 0,0; OVER 1;i$: BRIGHT 0: BORDER 0: CLS : POKE 23624,0
 9510 RETURN 
 9998 SAVE "crasher" LINE 9999

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top