Breakout

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

This program implements a Breakout-style game called “Demolition” in which a ball is dropped from a horizontally-moving cursor to destroy blocks arranged in coloured rows on screen. The game uses SCREEN$ to detect block collisions and implements a splash-damage mechanic in subroutine at line 700, clearing surrounding cells in a radius of up to five characters from the impact point. A UDG character (“g”) is defined at line 8000 as a solid rectangular block (six full-width scan lines between two blank rows) and used to draw the brick wall. Score digits are rendered into the display file directly by copying font data from the system character set via the ROM font address in system variable 23606/23607, writing pixel rows to a fixed screen address at line 4050. The ball speed is controlled by PAUSE p and a BEEP call each step, and the game tracks both current score and a persistent high score across rounds.


Program Analysis

Program Structure

The program is organised into several functional regions, entered non-linearly via GO TO chains:

  1. Lines 10–95: Title screen, instructions, and initialisation.
  2. Lines 100–398: Main game loop — ball movement left/right and drop trigger.
  3. Lines 500–780: Ball drop, collision detection, and splash-damage scoring.
  4. Lines 1000–1110: Wall rebuild trigger; manages level count and speed.
  5. Lines 2100–2190: Wall drawing using UDG “g” in five coloured rows.
  6. Lines 3000–3030: Game-over screen; prompts replay.
  7. Lines 4000–4100: Score rendering subroutine (direct display-file font copy).
  8. Lines 8000–8100: UDG definition and system-variable initialisation.

Initialisation and UDG Definition

Execution begins at line 190 with GO TO 8000. Lines 8000–8060 define UDG “g” as a block character: scan lines 0 and 7 are set to BIN 00000000 (blank) and lines 1–6 to BIN 01111110 (six pixels wide), producing a rectangular brick tile. Line 8080 reads the ROM font base address from system variables 23606/23607 into u, and line 8090 calculates a fixed display-file address v at screen row 0, column 6 (pixel address 16384 + 16*256 + 32*6 = 16576 + 192 = wait — 16384 + 256*16 + 32*6 = 16384 + 4096 + 192 = 20672), used as the score display area.

Ball Movement

The paddle/launcher is simulated by a * character sliding across row 1. Direction is chosen randomly at line 240 via INT(RND*2). In the rightward pass (lines 300–348), the cursor advances using CHR$ 8 (backspace) to erase and redraw the asterisk one column at a time. The leftward pass (lines 350–398) uses two consecutive CHR$ 8 characters to step back two positions (erase then move left). Each step calls BEEP .01,16 and PAUSE p; p starts at 1 and the speed mechanic is managed through k at line 1100.

Pressing key 6 at any step (checked via INKEY$ at lines 312, 332, 362, 382) triggers the drop routine at line 500.

Drop and Collision Detection

Line 510 computes the ball’s column using PEEK 23688, the system variable holding the current print column, subtracting 1: LET x=33-PEEK 23688-1. The ball then falls from row 2 to row 20, checking SCREEN$(i,x) at each step. A non-space character signals a brick hit; the ball stops and scoring begins.

Splash-Damage Mechanic

Lines 700–780 implement an expanding-radius explosion. After a direct hit, the loop at lines 720–780 iterates j from 1 to 5, checking cells diagonally above-left and above-right of impact. Variables sm, tm, sp, tp are Boolean flags (0 or 1 in Spectrum BASIC) indicating whether those cells are blank (already cleared). Their sum w counts remaining bricks in the splash zone; if w=0 the loop exits early. Each cleared brick awards 10 points (s=s+w*10).

This is a notable algorithmic feature — most BASIC Breakout clones do not implement area-effect scoring.

Score Rendering (Subroutine at Line 4000)

Rather than using PRINT AT for the score, the subroutine at line 4000 manually copies font bitmap data into the display file. For each digit character in STR$ s, it reads 8 scan-line bytes from the ROM font (base address u, offset f*8 per character) and POKEs them directly into display file addresses at row 2 (address v + j - 1 + 256*i). This bypasses the BASIC print system entirely and renders the score at pixel level, allowing placement in any screen area without attribute interference.

Wall Drawing

Lines 2100–2180 draw 16 blank rows followed by 5 rows of UDG “g” characters, each in a different INK colour (0–4, derived from i-16). The wall string a$ is 32 copies of \g (UDG “g”), filling the full screen width. After drawing, execution falls through to GO TO 200 to start the game loop.

Level Progression

Variable k counts how many times all bricks in row 1 have been cleared (detected at lines 210–213 by scanning SCREEN$(1,i) for a space). When c=k the wall is redrawn. k starts at 8 and decreases by 1 each cycle at line 1100, floored at 3, implying the game gets harder (fewer redraws before a new wall). Variable a counts redraws and changes the wall colour at a=5; at a=10 it resets.

Key Variables

VariablePurpose
sCurrent score
zHigh score (persists across rounds)
cClear counter (triggers wall rebuild at c=k)
kClears required per level; decreases each cycle
aWall colour cycle counter
pPAUSE duration (ball speed control)
uROM font base address
vDisplay file address for score rendering
xBall column on drop, from PEEK 23688

Bugs and Anomalies

  • Variables a$ and b$ are defined inside the wall-drawing block (lines 2100–2110) but are also referenced at lines 1010–1022, which execute before line 2100 in subsequent cycles — on the first pass this is safe because line 8100 routes to 2100 first, but b$ and a$ would be undefined if the code path ever reached line 1000 before 2100. In practice the flow is always 8100→2100→200→…→1000→200→…→2100, so it works.
  • Line 510 uses PEEK 23688 to find the current print column. System variable 23688 (SCRCT) is the scroll counter, not the print column. The actual print column is at system variable 23688 — on the Spectrum, 23688 is indeed not a standard column register. The correct variables are 23688 (SCRCT) vs 23689 (ATTR_P). The intended variable for column is 23689 or the 23688 family; this may work incidentally due to side effects of the PRINT statements setting internal state, but is architecturally questionable.
  • Line 552 prints a blank at row 20 after the loop exhausts without a hit, cleaning up the ball — correct behaviour.
  • The POKE 23692,255 calls at lines 1010 and 1022 reset the scroll counter to suppress the “scroll?” prompt, a standard Spectrum idiom.

Content

Appears On

This tape is a compilation of programs from user group members (Robert Burton, David Baulch, Frank Bouldin, Chuck Dawson, Ryan
One of a series of library tapes. Programs on these tapes were renamed to a number series. This tape contained

Related Products

Related Articles

Related Content

Image Gallery

Breakout

Source Code

   10 REM  "breakout" game
   20 CLS 
   40 RANDOMIZE 
   45 LET z=0: LET q$="Hi Score: "
   50 BORDER 6
   60 PRINT AT 6,6; INK 7; PAPER 1;" D E M O L I T I O N "
   70 REM 
   80 PRINT AT 16,6;"Press ENTER to Start"
   85 PRINT AT 21,4;"Use '6' key to Drop Ball"       
   90 INPUT LINE l$
   95 CLS 
  100 LET c=0: LET k=8: LET a=0: LET s=0: LET p=1
  190 GO TO 8000
  200 REM 
  202 GO SUB 4000
  210 FOR i=0 TO 31
  211 IF SCREEN$ (1,i)="" THEN GO TO 3000
  213 NEXT i
  220 LET c=c+1: IF c=k THEN GO TO 1000
  240 LET vv=INT (RND*2)
  245 PRINT AT 0,0;q$;z
  250 IF vv=0 THEN GO TO 300
  260 GO TO 350
  300 REM go right
  310 PRINT AT 1,0;"*";
  312 IF INKEY$="6" THEN GO TO 500
  320 FOR i=1 TO 31
  322 BEEP .01,16: PAUSE p
  330 PRINT CHR$ 8;" ";" ";CHR$ 8;"*";
  332 IF INKEY$="6" THEN GO TO 500
  340 NEXT i
  342 PRINT CHR$ 8;" ";
  348 GO TO 200
  350 REM go left
  360 PRINT AT 1,31;"*";
  362 IF INKEY$="6" THEN GO TO 500
  370 FOR i=0 TO 30
  372 BEEP .01,16: PAUSE p
  380 PRINT CHR$ 8;" ";CHR$ 8;CHR$ 8;"*";
  382 IF INKEY$="6" THEN GO TO 500
  390 NEXT i
  392 PRINT CHR$ 8;" ";
  398 GO TO 200
  500 REM drop
  510 LET x=33-PEEK 23688-1
  520 FOR i=2 TO 20
  530 PRINT AT i-1,x;" ";
  540 IF SCREEN$ (i,x)="" THEN GO TO 700
  542 PRINT AT i,x;"*": BEEP .01,8
  550 NEXT i
  552 PRINT AT 20,x;" ";
  560 GO TO 200
  700 REM 
  710 PRINT AT i,x;" ": LET s=s+10: BEEP .02,16
  711 IF s>z THEN LET z=s
  712 LET i=i+1: IF i>21 THEN GO TO 720
  714 IF SCREEN$ (i,x)="" THEN LET s=s+10
  716 PRINT AT i,x;" ";
  720 FOR j=1 TO 5
  722 LET xm=x-j: IF xm<0 THEN LET xm=0
  724 LET xp=x+j: IF xp>31 THEN LET xp=31
  726 LET sm=(SCREEN$ (i-j,xm)="")
  727 LET tm=(SCREEN$ (i-j-1,xm)="")
  728 LET sp=(SCREEN$ (i-j,xp)="")
  729 LET tp=(SCREEN$ (i-j-1,xp)="")
  730 LET w=sm+sp+tm+tp
  740 IF w=0 THEN GO TO 200
  760 PRINT AT i-j,xm;" ";: PRINT AT i-j,xp;" ";
  770 PRINT AT i-j-1,xm;" ";: PRINT AT i-j-1,xp;" ";
  772 LET s=s+w*10: BEEP .05,4
  775 IF s>z THEN LET z=s
  780 NEXT j
 1000 LET c=0: LET a=a+1: IF a>5 THEN GO TO 1020
 1010 POKE 23692,255: PRINT AT 21,31;b$: PRINT AT 20,0;b$: GO TO 1100
 1020 LET q=INT (RND*7)
 1022 POKE 23692,255: PRINT AT 21,31;b$: PRINT INK q;AT 20,0;a$: IF a=10 THEN LET a=0
 1100 LET k=k-1: IF k=2 THEN LET k=3
 1110 GO TO 200
 2100 LET a$="\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g"
 2110 LET b$="        "
 2112 LET z$="   Press ENTER to Play Again!   "
 2120 FOR i=0 TO 15
 2130 PRINT b$
 2140 NEXT i
 2150 FOR i=16 TO 20
 2160 PRINT INK (i-16);a$
 2170 NEXT i
 2180 PRINT b$
 2190 GO TO 200
 3000 REM stop
 3010 PRINT AT 21,0;z$
 3024 PRINT AT 0,0;q$;s
 3030 GO TO 90
 4000 REM score
 4020 LET s$=STR$ s: LET l=LEN s$
 4030 FOR j=1 TO l
 4040 LET f=CODE s$(j)
 4050 FOR i=0 TO 7: LET e=PEEK (u+f*8+i): POKE (v+j-1+256*i),e: NEXT i
 4060 NEXT j
 4100 RETURN 
 8000 LET g0=BIN 00000000
 8010 LET g1=BIN 01111110
 8020 POKE USR "g"+0,g0
 8030 FOR i=1 TO 6
 8040 POKE USR "g"+i,g1
 8050 NEXT i
 8060 POKE USR "g"+7,g0
 8080 LET u=PEEK (23607)*256+PEEK (23606)
 8090 LET v=16*256+32*6+16384
 8100 GO TO 2100

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

People

No people associated with this content.

Scroll to Top