This program implements a space shooter game where the player controls a cannon (UDG “a”) at the bottom of the screen, firing projectiles (UDG “b”) upward to hit stars (UDG “c”) arranged in four scrolling rows. Three custom UDG characters are defined via POKE USR: a triangular cannon shape, a vertical bullet, and an eight-pointed star. The four rows of stars scroll horizontally at different rates — row k shifts by k characters every 50 timer ticks — creating increasing difficulty. The STICK command (encoded as |) reads joystick input for movement and firing, and the score increments by 100 for each successful hit, with the time limit extending by 500 ticks each wave.
Program Analysis
Program Structure
The program is organized into clearly separated segments by line number range:
- 200–300: Initialization — screen clear, variable setup, score label.
- 500–770: UDG character definition via
POKE USR. - 900–980: Wave initialization — star array reset, initial star placement, screen draw.
- 1010–1310: Main game loop — joystick polling, player movement, projectile update, timing logic.
- 3000–3070: Subroutine: populate star field array.
- 4000–4030: Subroutine: render all four star rows to screen.
- 5000–5080: Subroutine: scroll star rows.
- 6000–6130: Subroutine: collision detection between projectile and stars.
- 7000–7030: Subroutine: score update and sound effect.
- 9000–9020: End-of-level handler, resets and restarts game.
UDG Character Definitions
Three User-Defined Graphics are created using POKE USR and BIN literals:
| UDG | Purpose | Description |
|---|---|---|
\a | Cannon / player | Wide triangle shape, narrow top, broad base — resembles a spaceship or cannon barrel. |
\b | Projectile / bullet | Thin vertical line with a slight fork at the bottom — a stylized missile. |
\c | Star / target | Radiating pattern with a solid cross and diagonal hints — an 8-point star. Note: line 710 contains BIN 011111110 (9 digits), which the interpreter silently truncates to 8 bits, effectively the same as BIN 11111110. |
Joystick Input via STICK
The program uses the TS2068 STICK keyword (encoded as | in the source). |(1,1) polls joystick port 1: a return value of 4 moves the cannon left (line 1010), 8 moves it right (line 1020), and |(2,1)=1 on the second axis triggers a shot (line 1030). This makes the game entirely joystick-driven with no keyboard fallback.
Star Field and Scrolling
The star field is stored in a 4×32 string array a$, where each row corresponds to one of four display rows on screen, each separated by a blank line. The scrolling subroutine at line 5000 rotates row k left by k characters using string slicing — so row 1 scrolls slowest and row 4 scrolls fastest. This differential scrolling is achieved with:
h$=a$(k,1 TO k)— save the leadingkcharacters.a$(k,1 TO 32-k)=a$(k,k+1 TO 32)— shift left.a$(k,32-k+1 TO )=h$— wrap saved characters to the end.
Scrolling is triggered every 50 timer increments (checked at line 1265 with IF tm/50=INT(tm/50)), giving a periodic rather than continuous scroll.
Projectile and Collision Detection
When fired, the projectile starts at row 19, column sta (the cannon’s position) and moves up by 2 rows per loop iteration (LET s=s-2, line 1250). Collision is checked only when the projectile is in the upper half of the screen (s<=7) and on an odd row (s/2<>INT(s/2)), since star rows occupy rows 1, 3, 5, and 7. The subroutine at 6000 checks a$(k,c+1)="\c" for each of the four star rows: the column offset of c+1 is because the array is 1-indexed while screen columns are 0-indexed. A hit clears the array cell, erases the character from the screen, decrements left, and adds 100 to the score.
Wave Progression and Difficulty
The variable n controls the number of stars placed per wave, initialized to 15 and incremented by 5 each new wave up to a cap of 100 (line 3000). The time limit limit is extended by 500 ticks per wave. The condition at line 1270 (IF tm=limit) ends the current wave and loops back to line 200 for a full reset rather than continuing from where the player left off — meaning there is no persistent score accumulation across waves.
Notable Bugs and Anomalies
- Line
1280checksIF left=0 THEN GO TO 1300, but line1300is simplyGO TO 1010— the branch to1300is identical in behavior to falling through to line1290, which also goes to1010. The intent may have been to trigger a new wave when all stars are cleared, but lines1310–1320(which callGO SUB 4000and loop back) are never reached by any execution path. - Line
710usesBIN 011111110, a 9-bit binary literal. The interpreter reads only the rightmost 8 bits, yielding11111110(254) instead of the likely intended01111110(126). This causes the top of the star UDG to have its leftmost pixel lit unexpectedly. - The projectile column variable is named
c, which shadows no keyword but is also used without initialization ifpris ever non-zero from a prior cycle without a fresh shot — in practice the flow prevents this.
Content
Source Code
200 DIM a$(4,32)
220 LET n=15
230 LET tm=0
240 LET s$=" "
245 PAPER 1: BRIGHT 1
250 FOR j=0 TO 21
260 PRINT AT j,0;s$;s$
270 NEXT j
280 LET pr=0
290 INK 7: PRINT AT 21,11;"Score "
300 LET limit=800
500 POKE USR "a",BIN 00011000
510 POKE USR "a"+1,BIN 00011000
520 POKE USR "a"+2,BIN 00111100
530 POKE USR "a"+3,BIN 00111100
540 POKE USR "a"+4,BIN 01111110
550 POKE USR "a"+5,BIN 01100110
560 POKE USR "a"+6,BIN 11000011
570 POKE USR "a"+7,BIN 11000011
600 POKE USR "b",BIN 00011000
610 POKE USR "b"+1,BIN 00011000
620 POKE USR "b"+2,BIN 00011000
630 POKE USR "b"+3,BIN 00011000
640 POKE USR "b"+4,BIN 00011000
650 POKE USR "b"+5,BIN 00011000
660 POKE USR "b"+6,BIN 00100100
670 POKE USR "b"+7,BIN 00000000
700 POKE USR "c",BIN 00000000
710 POKE USR "c"+1,BIN 011111110
720 POKE USR "c"+2,BIN 11111111
730 POKE USR "c"+3,BIN 00011000
740 POKE USR "c"+4,BIN 00111100
750 POKE USR "c"+5,BIN 01111110
760 POKE USR "c"+6,BIN 11111111
770 POKE USR "c"+7,BIN 00011000
900 LET sta=15
910 FOR i=1 TO 4
930 FOR j=1 TO 32
940 LET a$(i,j)=" "
950 NEXT j
960 NEXT i
970 LET scr=0
980 GO SUB 3000
985 GO SUB 4000
1010 IF |(1,1)=4 THEN GO TO 1100
1020 IF |(1,1)=8 THEN GO TO 1150
1030 IF |(2,1)=1 THEN GO TO 1060
1050 GO TO 1200
1060 LET pr=1: LET s=19: LET c=sta
1070 GO TO 1200
1100 IF sta-1<0 THEN GO TO 1200
1110 PRINT AT 20,sta;" "
1120 LET sta=sta-1
1130 GO TO 1200
1150 IF sta+1>31 THEN GO TO 1200
1160 PRINT AT 20,sta;" "
1170 LET sta=sta+1
1180 GO TO 1200
1200 INK 6: PRINT AT 20,sta;"\a"
1210 IF pr=0 THEN GO TO 1260
1220 IF s<=7 AND s/2<>INT (s/2) THEN GO SUB 6000
1230 INK 6: PRINT AT s,c;"\b"
1240 PAUSE 3: PRINT AT s,c;" "
1250 LET s=s-2
1260 LET tm=tm+8
1265 IF tm/50=INT (tm/50) THEN GO SUB 5000
1270 IF tm=limit THEN GO TO 9000
1280 IF left=0 THEN GO TO 1300
1290 GO TO 1010
1300 GO TO 1010
1310 GO SUB 4000
1320 GO TO 1010
3000 IF n<100 THEN LET n=n+5
3005 LET limit=limit+500: LET left=n
3010 FOR k=1 TO n
3020 LET x=INT (RND*4)+1
3030 LET y=INT (RND*32)+1
3040 IF a$(x,y)<>" " THEN GO TO 3020
3050 LET a$(x,y)="\c"
3060 NEXT k
3070 RETURN
4000 FOR k=1 TO 4
4010 INK 7: PRINT AT (k-1)*2+1,0;a$(k,1 TO 32)
4020 NEXT k
4030 RETURN
5000 FOR k=1 TO 4
5010 LET h$=a$(k,1 TO k)
5020 LET a$(k,1 TO 32-k)=a$(k,k+1 TO 32)
5030 LET a$(k,32-k+1 TO )=h$
5040 NEXT k
5050 GO SUB 4000
5080 RETURN
6000 FOR k=4 TO 1 STEP -1
6010 IF a$(k,c+1)="\c" AND s=(k-1)*2+1 THEN GO TO 6100
6020 NEXT k
6030 IF s>0 THEN RETURN
6040 GO TO 6120
6100 LET a$(k,c+1)=" "
6103 PRINT AT (k-1)*2+1,c;" "
6105 LET left=left-1
6110 LET scr=scr+100
6115 GO SUB 7000
6120 LET pr=0
6130 RETURN
7000 BEEP 0.01,2
7010 PRINT AT 21,17;scr
7020 FLASH 0
7030 RETURN
9000 BRIGHT 0
9010 INK 0
9020 GO TO 200
9997 SAVE "star blast"
9998 STOP
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

