Racer 2

This file is part of and Timex Sinclair Public Domain Library Tape 1005. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000
Tags: Arcade, Game

Racer 2 is a ZX81/TS1000 scrolling racing game in which the player steers a car left and right along a road while the road itself weaves randomly up the screen. The road is drawn each frame as a row of block-graphic characters at a horizontally drifting position, and the player’s car is printed one row above as an inverse-H character. Collision detection is performed via a PEEK of the display file: the program reads the two-byte D_FILE pointer from system variables at addresses 16398–16399 and checks whether the character under the car’s position equals 128 (a block graphic), halting the game on impact. Road drift is controlled by a pair of conditional nudges using RND, keeping variable D (column) within roughly 7–17 to constrain the road to a playable corridor.


Program Analysis

Program Structure

The program is a short main loop with initialisation at lines 20–50, a rendering and input phase at lines 60–130, a collision check at line 140, and a loop-back at line 150. Lines 160–170 are utility lines (save and auto-run) that are never reached during normal play.

  1. Initialisation (lines 20–50): Sets A=10 (car row), B=A (car column, starts at 10), C=A+A=20 (road row, near the bottom), D=9 (road column).
  2. Road drawing (line 60): Prints a road segment of block-graphic characters at row C (20), column D.
  3. Car drawing (line 70): Prints a block-graphic at the car’s current position row A, column B.
  4. Scroll and input (lines 80–100): Scrolls the screen up one line, then reads INKEY$ twice to move the car right (M) or left (Z).
  5. Car sprite (line 110): Redraws the car as an inverse-H character (%H) at the updated position.
  6. Road steering (lines 115–130): Nudges D upward if below 17, downward if above 7, using 2*RND fractional increments. Line 120 positions the print cursor without printing anything, possibly as a cursor-placement side-effect.
  7. Collision detection (line 140): Peeks the display file to detect a crash.

Display and Graphics

The road is rendered using ZX81 block-graphic characters (\## escapes, solid block character 128) surrounded by spaces, giving a short road segment roughly eight characters wide. The player’s car is a single inverse-H character (%H, i.e. character code for H in inverse video), visually distinct from the road graphics. The SCROLL command at line 80 moves all rows up, creating the illusion of forward movement.

Collision Detection Technique

Line 140 implements a display-file collision check, a classic ZX81 technique. PEEK 16398 and PEEK 16399 read the low and high bytes of the D_FILE system variable (the pointer to the display file in RAM). The combined 16-bit address PEEK 16398 + PEEK 16399 * 256 gives the start of the display file, and PEEK of that address checks the first character in the file. A value of 128 (the solid block graphic) indicates the car has hit the road and STOP ends the game.

There is a subtle anomaly here: the PEEK always reads the very first byte of the display file (the top-left cell), not the byte at the car’s current position. This means the collision check only triggers when a road block graphic has scrolled all the way to the top-left corner of the screen, rather than detecting a true overlap between car and road. As a result the game ends somewhat unpredictably rather than precisely on contact.

Road Drift Algorithm

The road column D is kept within a soft corridor of 7–17 by two opposing nudges per frame:

  • Line 115: if D < 17, add 2*RND (a random value in [0,2)).
  • Line 130: if D > 7, subtract 2*RND.

Because both conditions can be true simultaneously (when 7 < D < 17), both nudges apply each frame, producing a random walk bounded loosely between the two thresholds. The road therefore drifts smoothly but erratically across the screen.

Key BASIC Idioms

LineIdiomPurpose
80SCROLLShifts display up one row to simulate movement
90–100Back-to-back INKEY$ testsSingle-frame key polling without PAUSE
110%H inverse characterVisually distinct player sprite using inverse video
140PEEK(PEEK lo + PEEK hi * 256)Indirect address read via system variable pointer
115, 1302*RND fractional driftSmooth stochastic road steering

Bugs and Anomalies

  • The collision check at line 140 reads the first byte of the display file rather than the byte at the car’s screen position. A correct check would need to offset the pointer by the car’s row and column within the display file (accounting for the newline bytes that separate rows on the ZX81).
  • Line 120 (PRINT AT 11,B;) positions the print cursor at row 11 without outputting any character. This may be an artefact of an earlier version of the program or intended to pre-position the cursor, but it has no visible effect in the current flow.
  • The car column B is never range-checked, so pressing M or Z repeatedly can drive the car off the edges of the 32-column display, causing a potentially confusing wrap or error.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10211 – 10251.

Related Products

Related Articles

Related Content

Image Gallery

Racer 2

Source Code

  10 REM "RACER 2"
  20 LET A=10
  30 LET B=A
  40 LET C=A+A
  50 LET D=9
  60 PRINT AT C,D;"% \##\##\##\##% "
  70 PRINT AT A,B;"\##"
  80 SCROLL 
  90 IF INKEY$="M" THEN LET B=B+1
 100 IF INKEY$="Z" THEN LET B=B-1
 110 PRINT AT A,B;"%H"
 115 IF D<17  THEN LET D=D+2*RND
 120 PRINT AT 11,B;
 130 IF D>7 THEN LET D=D-2*RND
 140 IF PEEK (PEEK 16398+PEEK 16399*256)=128 THEN STOP 
 150 GOTO 60
 160 SAVE "1022%3"
 170 RUN 

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

People

No people associated with this content.

Scroll to Top