ANIMATION

Developer(s): Duncan Overton
Date: 1984
Type: Program
Platform(s): TS 2068
Tags: Art

This program creates a rotating animation of geometric shapes — concentric circular arcs and line segments drawn using trigonometric PLOT and DRAW commands — and cycles through four animation frames using machine code screen-copy routines. The program draws four slightly offset elliptical arcs (INK 6), a quarter-circle arc (INK 5), and a smaller quarter-circle (INK 2) for each frame, with each successive frame rotated by PI/32 radians. Machine code poked into address 64000 performs fast block memory copies between the display file at address 16384 and four frame buffers starting at address 32000, each 7000 bytes apart. After all four frames are drawn and stored, a second machine code routine at 64000–64080 cycles through the frames continuously until a keypress is detected, at which point the animation loops.


Program Structure

The program divides into three logical phases:

  1. Frame generation (lines 80–240): Four animation frames are drawn using PLOT/DRAW and each is copied from the display file into an off-screen buffer via machine code.
  2. Machine code copy-to-buffer subroutine (lines 260–280): Pokes a Z80 routine into address 64000 that copies the current display (at 16384) into one of four 7000-byte buffers starting at 32000.
  3. Playback loop (lines 290–380): A second machine code routine is assembled in place that copies each buffer back to the display file in rapid succession, looping until a key is pressed.

Frame Drawing

Each frame plots four nearly coincident arcs of a large ellipse using INK 6, stepping from 0+d to 2*PI+d in increments of PI/8. The four arcs are offset from each other by PI/100, PI/50, and 3*PI/100 radians, creating a thick-band appearance. A PI/2-long arc at radius 70 (INK 5) and a shorter arc at radius 35 (INK 2) are also drawn, giving the impression of rotating clock-hand segments. After each frame, the frame offset d is incremented by PI/32, rotating all geometry for the next frame.

Machine Code Usage

Two distinct machine code routines are poked into RAM at address 64000. Both implement Z80 block-copy loops but in opposite directions.

Copy-to-buffer routine (subroutine at line 260):

The DATA at line 270 encodes a Z80 routine that copies 27×256 bytes from address 16384 (the display file) to one of the four frame buffers. The source address low and high bytes are computed from z as z - INT(z/256)*256 and INT(z/256) — a standard BASIC modulo-256 trick. The outer loop register B is set to 27, the inner to 0 (256 iterations), giving 6912 bytes copied, exactly one Spectrum display file. The instruction sequence is approximately:

  • LD DE, buffer_address (destination)
  • LD HL, 16384 (source: display file)
  • Outer loop (B=27): inner loop (B=0→256): LD A,(DE), LD (HL),A, INC DE, INC HL, DJNZ inner
  • RET

Note the DATA at line 270 actually has source and destination swapped from the playback routine — it reads from HL (display) and writes to DE (buffer).

Playback routine (lines 300–360):

Three copies of a similar routine are assembled consecutively at 64000, 64020, and 64040, each copying one buffer back to the display file (DE=source buffer, HL=16384 destination). After all three are poked, a RET opcode (201) is poked at 64080 to terminate the chain. RANDOMIZE USR 64000 executes the full sequence: three screen swaps in rapid succession produce the animation effect. The loop at line 360 re-executes USR 64000 on each iteration while no key is held, and line 370 waits for the key to be fully released before looping back.

Key BASIC Idioms

  • z - INT(z/256)*256 and INT(z/256) — BASIC’s way of computing the low and high bytes of a 16-bit address for embedding in machine code DATA.
  • RESTORE before each DATA read ensures the correct DATA block is re-read despite multiple calls.
  • RANDOMIZE USR addr — the standard idiom for calling machine code while discarding the return value.
  • IF INKEY$="" THEN ... : IF INKEY$<>"" THEN GO TO 370 — a debounce loop that waits for a key down then waits for key release before exiting animation.

Notable Techniques

  • Using CLEAR 63999 reserves the top of RAM (from 64000 upward) as a safe machine code workspace without interfering with BASIC.
  • The four off-screen buffers at 32000, 39000, 46000, and 53000 each require 7000 bytes; the Spectrum display file is 6912 bytes, so 7000 provides a small safety margin between buffers.
  • Drawing four nearly identical arcs offset by tiny angles achieves antialiasing-like line thickening entirely within BASIC.

Bugs and Anomalies

  • Only three of the four frames are played back in the animation loop (lines 300–340 iterate f = 0, 20, 40), installing three routines at offsets 0, 20, and 40 from 64000. The fourth frame buffer (at 53000) is never displayed, meaning the animation shows only three of the four drawn frames.
  • The DATA at line 270 embeds z as a live variable reference. Because BASIC evaluates the DATA values at read time (via READ q), this works correctly — the current value of z is substituted each time the subroutine is called after updating z at line 210.
  • Similarly, line 320 embeds z directly in DATA; this relies on the same read-time evaluation and is updated correctly by the LET z=z+7000 at line 330 between loop iterations.

Image Gallery

Source Code

  10 REM >>  ANIMATION  <<       
  30 REM © ZX COMPUTING,                  Feb/Mar 1984.         BY  Duncan Overton, England      
  50 BORDER 0:PAPER 0:BRIGHT 1:CLS 
  60 OVER 0:CLEAR 63999
  70 REM Copies four screens in memory  and then prints them one after  another to make an animation    effect
  80 LET z=32000:LET d=0
  90 FOR m=1 TO 4
 100 FOR n=0+d TO 2* PI+d STEP PI/8
 110 INK 6:PLOT 127+127* SIN n,87+87* COS (n)
 120 INK 6:PLOT 127+127* SIN (n+ PI/100),87+87* COS (n+ PI/100)
 130 INK 6:PLOT 127+127* SIN (n+ PI/50),87+87* COS (n+ PI/50)
 140 INK 6:PLOT 127+127* SIN (n+3* PI/100),87+87* COS (n+3* PI/100)
 150 INK 5:PLOT 127+70* SIN -n,87+70* COS -n
 160 DRAW 70*(SIN (-n+ PI/2)- SIN -n),70*(COS (-n+ PI/2)- COS -n)
 170 INK 2:PLOT 127+35* SIN n,87+35* COS n
 180 DRAW 35*(SIN (n+ PI/2)- SIN n),35*(COS (n+ PI/2)- COS n)
 190 NEXT n
 200 GO SUB 260
 210 LET z=z+7000
 220 LET d=d+ PI/32
 230 CLS 
 240 NEXT m
 250 GO TO 290
 260 RESTORE 270:FOR n=64000 TO 64020:READ q:POKE n,q:NEXT n:RANDOMIZE USR 64000
 270 DATA 17,0,64,33,z- INT (z/256)*256, INT (z/256),6,27,197,6,0,26,119,19,35,16,249,193,16,244,201
 280 RETURN 
 290 LET z=32000
 300 FOR f=0 TO 60 STEP 20
 310 RESTORE 320:FOR n=64000+f TO 64019+f:READ q:POKE n,q:NEXT n
 320 DATA 17,z- INT (z/256)*256, INT (z/256),33,0,64,6,27,197,6,0,26,119,19,35,16,249,193,16,244
 330 LET z=z+7000
 340 NEXT f
 350 POKE 64080,201
 360 IF INKEY$="" THEN RANDOMIZE USR 64000
 370 IF INKEY$ <>"" THEN GO TO 370
 380 GO TO 360

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