Invader

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

This program implements a scrolling starfield or “space” screen effect combined with a falling-object mechanic on a ZX81/TS1000. Lines 5–7 fill the screen with inverse-space characters to create a background, and lines 100–299 sweep through every print position in a double loop, drawing a moving marker that advances diagonally each frame. A keypress (detected via INKEY$) triggers a “bullet” or object that travels down and right, drawn with a block-graphic character (▖), until it reaches row 15 where a GOSUB resets it. After the main loop, lines 300–330 scan the bottom row for a specific character (PEEK value 128) to detect a collision or boundary condition, then the program pauses and restarts via RUN.


Program Analysis

Program Structure

The program is divided into five functional blocks:

  1. Screen initialisation (lines 5–11): Fills the screen with inverse-space characters and draws two decorative border rows using block graphics.
  2. Main animation loop (lines 100–299): A nested loop over rows P (1–15) and columns Q (1–30) sweeps a marker across every cell, while optionally tracking and advancing a secondary “projectile” object.
  3. Bottom-row collision check (lines 300–340): Scans along row 16 (P retains value 16 after the loop) looking for a specific display-file byte value.
  4. Reset and restart (lines 341–342): Clears the screen and restarts the whole program.
  5. Subroutine and save block (lines 400–450): A short GOSUB resets the projectile state; lines 430–450 handle CLEAR/SAVE/RUN for program persistence (never reached in normal execution).

Initialisation Detail

Lines 5–7 loop 15 times printing a full row of inverse-space characters (% ), effectively painting the upper screen region solid black. CLEAR at line 8 resets variables without clearing the display. LET B=VAL "0" initialises the projectile-active flag; using VAL "0" rather than a bare literal is a minor memory optimisation that stores a string constant instead of a floating-point number in the token stream. Line 10 prints a row of inverse O characters and line 11 prints 32 repetitions of the block graphic (\~~ escape) to form a decorative bottom border.

Main Loop and Sweep Marker

The nested loops at lines 100–299 iterate P from 1 to 15 and Q from 1 to 30. At each position, line 120 erases the previous cell with a space, and line 280 redraws it with an inverse-space pair (% ), creating a sweeping highlight effect across the screen.

Projectile / Object Mechanic

Flag variable B tracks whether a projectile is in flight. While B=0, line 130 watches for a keypress via INKEY$; if a key is pressed (and the sweep has not yet reached row 7), the current position is latched into R (row) and S (column) and B is set to 1. Each iteration of the inner loop then advances the projectile diagonally: R increments by 1 and S by 1, with S wrapping to 0 when it exceeds 30 (line 143). The projectile is drawn with the graphic (\. : escape, line 145). When R reaches 15 the subroutine at line 400 erases it and resets B=0.

There is a subtle anomaly on line 130: the condition P=7 forces a jump to line 150 (which does not exist), causing the program to fall through — a deliberate or accidental use of a non-existent line target as a no-op branch. Additionally, the condition INKEY$="" is logically inverted from what might be expected: the branch fires when no key is pressed, meaning the latch only triggers when the key is actually held down and the condition is false.

Collision / Boundary Detection

After the nested loops, P holds 16 (the post-loop value). Lines 300–330 iterate Q from 0 to 30, reading the ZX81 display file byte at the current cursor position via PEEK (PEEK 16398 + 256*PEEK 16399). System variables at addresses 16398–16399 hold the display-file base address (D-FILE pointer). A value of 128 (inverse space) is the test condition; if found the loop exits early via GOTO 340, otherwise it continues to the end. After the scan, the program pauses 250 frames, clears, and restarts.

Key Variables

VariableRole
BProjectile active flag (0 = idle, 1 = in flight)
POuter loop row counter (sweep); also row index for bottom scan
QInner loop column counter (sweep and bottom scan)
RProjectile current row
SProjectile current column (wraps at 30)
ZCounter for initial screen-fill loop (lines 5–7)

Notable Techniques

  • VAL "n" used in loop limits and initialisations to save tokenised number storage space.
  • Direct display-file PEEKing through the D-FILE system variable pointer (16398/16399) for hardware-level character detection without any collision array.
  • Block graphic used as a visually distinct projectile sprite within the constraints of character-cell graphics.
  • The SAVE "1026%3" at line 440 (inverse 3 in the filename) sets the auto-run flag so the program restarts automatically when loaded.
  • Diagonal projectile movement using simultaneous row and column increments within the same loop iteration, with column wrap-around handled by a single conditional.

Bugs and Anomalies

  • Line 130 branches to line 150 on P=7, but line 150 does not exist; on a ZX81 this causes an error or unexpected behaviour rather than a clean skip.
  • The logic of line 130 means the keypress latch at lines 131–133 is only reached when INKEY$ is not empty (key held) and P≠7, which may be intentional but reads counter-intuitively given the combined OR condition.
  • Line 145 draws the projectile after line 140 may have already drawn an inverse-space at the same position; depending on execution order within the loop, the projectile could be overwritten by the sweep marker on the same pass.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10252 – 10293.

Related Products

Related Articles

Related Content

Image Gallery

Invader

Source Code

   5 FOR Z=VAL "1" TO VAL "15"
   6 PRINT "% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
   7 NEXT Z
   8 CLEAR 
   9 LET B=VAL "0"
  10 PRINT "%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O%O"
  11 PRINT "\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~"
 100 FOR P=VAL "1" TO VAL "15"
 110 FOR Q=1 TO 30
 120 PRINT AT P,Q;" "
 125 IF B THEN GOTO 140
 130 IF INKEY$="" OR P=7 THEN GOTO 150
 131 LET R=P
 132 LET S=Q
 133 LET B=1
 140 PRINT AT R,S;"% "
 141 LET R=R+1
 142 LET S=S+1
 143 IF S>30 THEN LET S=0
 145 PRINT AT R,S;"\.:"
 146 IF R=15 THEN GOSUB 400
 280 PRINT AT P,Q;"% "
 290 NEXT Q
 299 NEXT P
 300 FOR Q=0 TO 30
 310 PRINT AT P,Q;" "
 320 IF 128<>PEEK (PEEK 16398+256*PEEK 16399) THEN GOTO 340
 330 NEXT Q
 340 PAUSE 250
 341 CLS 
 342 RUN 
 400 PRINT AT R,S;"% "
 410 LET B=0
 420 RETURN 
 430 CLEAR 
 440 SAVE "1026%3"
 450 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