Manimate

Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Animation

Animates a small man, drawn from user-defined graphics, who marches down the screen and then along the bottom row. Each pass stops three columns short of the one before, until he no longer moves. Holding down a key removes the delay between frames. The figure has more animation frames than the 21 UDG slots can hold, so the program sets up four separate UDG banks in high memory and switches between them in mid-animation by POKEing the UDG pointer at 23675/23676.

MANIMATE appeared in Volume 6 of the CATS 2068 Software Library, where John Riley’s article introducing Volumes Six and Seven describes it as a demo showing how BASIC can bring "a spritely little marching man" to life. The copy archived here doesn’t run as it stands. It stops with an Out of DATA error before the animation starts (see Potential Issues).

Program Analysis

Program Structure

  • Line 10: CLEAR 64699 and sets l, the column where the march along the bottom stops, to 29.
  • Lines 20–30: fill d$(24,3) with the frames for the march down. Each frame is three rows of two characters.
  • Lines 40–50: read 20 UDGs each into banks at 65200 and 65029, then point the UDG pointer back at the default 65368.
  • Lines 60–70: fill e$(24,3) with the two-row frames for the march along the bottom.
  • Lines 80–90: read 21 UDGs each into banks at 64861 and 64693.
  • Lines 100–120: add 79 to every non-space character code in d$ and e$, to turn the letters into UDG codes.
  • Lines 130–160: march down from row 10 to row 18 at column 2, cycling through eight three-row frames and changing bank halfway through the cycle.
  • Lines 170–220: march along rows 19–20 from column 2 to column l, cycling through ten two-row frames and changing bank at frame 11, then turn back to the standing pose.
  • Lines 230–250: take 3 off l and repeat until l reaches 2.
  • Lines 1000–1430: the UDG bitmap data.

Notable Techniques

  • Each bank is loaded by setting the pointer and then using the usual POKE USR CHR$ i+j,a loop for codes 144–164, so the same loop fills whichever bank the pointer currently addresses.
  • Switching banks takes one or two POKEs, so the animation gets 82 character cells of graphics where a single UDG set would give 21.
  • IF INKEY$="" THEN PAUSE 20 slows each frame unless a key is held down.

Potential Issues

  • The DATA runs out. The four banks need 656 values (2 × 20 × 8 plus 2 × 21 × 8), but lines 1000–1430 hold 651. Line 1110 is missing from the otherwise regular numbering, so a DATA line may have been lost. In ZEsarUX the program stops with "E Out of DATA, 90:3", and the variables saved on the tape show it was saved after the same error.
  • Line 120 reads NEXT x: NEXT y although y is the inner loop. Since a Sinclair NEXT returns to the statement after its own FOR, only the first column is converted while x counts. NEXT y then re-enters line 100 with x=25, which is past the end of the arrays.
  • Line 100 adds 79 to codes that are lower-case letters, which gives codes from 176 upward. Those are keyword tokens, not UDGs (144–164); that offset fits upper-case letters. The strings may originally have been typed in upper case.
  • The fourth bank starts at 64693, below the RAMTOP set by CLEAR 64699, so its first bytes fall outside the protected area.
  • The program was saved without an autostart line and has to be started with RUN.

Related Articles

After several months of collecting new software from contributors across the country, here are the latest additions to the 2068 library!

Source Code

   10 CLEAR 64699: LET l=29
   20 DIM d$(24,3): LET d$(1)="ab": LET d$(2)="cd": LET d$(3)="  ": LET d$(4)="ef": LET d$(5)="gh": LET d$(6)=" i": LET d$(7)="jk": LET d$(8)="lm": LET d$(9)=" n": LET d$(10)="op": LET d$(11)="qr": LET d$(12)="st"
   30 LET d$(13)="ab": LET d$(14)="cd": LET d$(15)="ef": LET d$(16)="gh": LET d$(17)="ij": LET d$(18)="kl": LET d$(19)="  ": LET d$(20)="mn": LET d$(21)="op": LET d$(22)="  ": LET d$(23)="qr": LET d$(24)="st"
   40 POKE 23675,176: POKE 23676,254: FOR z=1 TO 2: IF z=2 THEN POKE 23675,5
   50 FOR i=144 TO 163: FOR j=0 TO 7: READ a: POKE USR CHR$ i+j,a: NEXT j: NEXT i: NEXT z: POKE 23675,88: POKE 23676,255
   60 DIM e$(24,3): LET e$(1)="ab ": LET e$(2)="cd ": LET e$(3)="ef ": LET e$(4)="gh ": LET e$(5)="ij ": LET e$(6)="kl ": LET e$(7)="mn ": LET e$(8)="op ": LET e$(9)="qr ": LET e$(10)="st ": LET e$(11)=" u ": LET e$(12)=" a "
   70 LET e$(13)=" b ": LET e$(14)=" c ": LET e$(15)=" d ": LET e$(16)=" e ": LET e$(17)=" fg": LET e$(18)=" hi": LET e$(19)=" jk": LET e$(20)=" lm": LET e$(21)=" no": LET e$(22)=" pq": LET e$(23)=" rs": LET e$(24)=" tu"
   80 POKE 23675,93: POKE 23676,253: FOR z=1 TO 2: IF z=2 THEN POKE 23675,181: POKE 23676,252
   90 FOR i=144 TO 164: FOR j=0 TO 7: READ a: POKE USR CHR$ i+j,a: NEXT j: NEXT i: NEXT z
  100 FOR x=1 TO 24: FOR y=1 TO 3: IF CODE d$(x,y)<>32 THEN LET d$(x,y)=CHR$ (CODE d$(x,y)+79)
  110 IF CODE e$(x,y)<>32 THEN LET e$(x,y)=CHR$ (CODE e$(x,y)+79)
  120 NEXT x: NEXT y
  130 POKE 23676,254: FOR i=10 TO 18: POKE 23675,176: FOR j=1 TO 22 STEP 3: IF j=13 THEN POKE 23675,5
  140 IF INKEY$="" THEN PAUSE 20
  150 PRINT AT i,2;d$(j): PRINT AT i+1,2;d$(j+1): PRINT AT i+2,2;d$(j+2)
  160 PAUSE 7: NEXT j: NEXT i
  170 POKE 23675,93: POKE 23676,253: PRINT AT 19,2;e$(1): PRINT AT 20,2;e$(2): PAUSE 10: PRINT AT 19,2;e$(3): PRINT AT 20,2;e$(4): PAUSE 10
  180 FOR i=2 TO l: POKE 23675,93: POKE 23676,253: FOR j=5 TO 24 STEP 2
  190 IF INKEY$="" THEN PAUSE 20
  200 PRINT AT 19,i;e$(j): IF j=11 THEN POKE 23675,181: POKE 23676,252
  210 PRINT AT 20,i;e$(j+1): PAUSE 7: NEXT j: NEXT i
  220 POKE 23675,93: POKE 23676,253: PRINT AT 19,i;e$(3): PRINT AT 20,i;e$(4): PAUSE 5: PRINT AT 19,i;e$(1): PRINT AT 20,i;e$(2): PAUSE 10
  230 IF l=2 THEN STOP 
  240 LET l=l-3
  250 GO TO 130
 1000 DATA 0,1,2,2,1,6,10,18,0,128,64,64,128,96,80,72
 1010 DATA 128,17,2,2,2,2,2,2,72,136,64,64,64,64,64,64
 1020 DATA 0,0,0,1,2,2,1,6,0,0,0,128,64,64,128,96,10
 1030 DATA 18,34,33,2,3,1,0,80,72,80,144,64,64,64
 1040 DATA 64,64,64,0,0,0,0,0,0,0,0,0,0,0,1,2,2,0
 1050 DATA 0,0,0,0,128,64,64,1,6,10,17,34,1,3,1
 1060 DATA 128,96,80,72,80,160,64,64,64,64,64,0,0
 1070 DATA 0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,128,64
 1080 DATA 64,1,6,10,18,34,33,2,3,128,96,80,72,80
 1090 DATA 144,64,64,1,0,0,0,0,0,0,0,64,64,64,0,0
 1100 DATA 0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,128,64
 1120 DATA 64,1,6,10,18,18,17,2,2,128,96,80,72,72
 1130 DATA 136,64,64,2,2,2,0,0,0,0,64,64,64
 1140 DATA 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0
 1150 DATA 128,2,2,1,3,10,18,10,9,64,64,128,96,80
 1160 DATA 72,68,132,2,2,2,2,2,2,0,0,64,64,128,128
 1170 DATA 0,0,0,0,0,1,2,2,1,6,10,18,0,128,64,64
 1180 DATA 128,96,80,72,10,5,2,2,2,2,2,0,68,130
 1190 DATA 192,128,0,0,0,0,0,1,2,2,1,6,10,18,0,128
 1200 DATA 64,64,128,96,80,72,10,9,2,2,2,2,2,0,68
 1210 DATA 132,64,192,128,0,0,0,0,1,2,2,1,6,10,0
 1220 DATA 128,64,64,128,64,96,80,10,9,1,1,1,1,1,0
 1230 DATA 80,144,128,128,128,128,128,0,0,1,2,2,1
 1240 DATA 3,2,6,0,128,64,64,128,64,64,64,3,3,1,1
 1250 DATA 1,1,1,0,64,192,0,0,0,0,0,0,0,1,2,2,1,3
 1260 DATA 3,3,0,128,64,64,128,64,64,64,2,3,1,1,1
 1270 DATA 1,1,0,64,160,64,64,32,32,64,0,0,0,1,1,0
 1280 DATA 1,1,3,0,192,32,32,192,160,32,32,3,2,0,0
 1290 DATA 1,1,1,0,48,200,160,160,16,16,16,0,0,0,0
 1300 DATA 0,0,0,0,1,0,96,144,144,96,208,144,144,2
 1310 DATA 2,0,0,0,1,1,0,148,98,80,80,144,16,16,0
 1320 DATA 0,48,72,72,48,104,104,104,108,114,48,48
 1330 DATA 80,144,144,0,0,12,18,18,12,26,26,27,18
 1340 DATA 14,22,20,20,20,20,24,0,12,18,18,12,26
 1350 DATA 27,27,51,61,18,18,17,17,18,0,0,6,9,9,6
 1360 DATA 13,11,25,0,0,0,0,0,0,0,192,25,38,9,9,17
 1370 DATA 17,17,0,64,64,0,0,0,0,0,0,0,3,4,4,3,6,5
 1380 DATA 13,0,0,128,128,0,128,128,128,12,11,3,3
 1390 DATA 5,9,9,0,128,128,128,0,0,0,0,0,0,1,2,2,1
 1400 DATA 3,3,2,0,128,64,64,128,64,64,192,2,3,1,1
 1410 DATA 3,3,3,0,192,128,0,0,0,0,0,0,0,1,2,2,1,3
 1420 DATA 3,3,0,128,64,64,128,64,64,64,3,1,1,1,1
 1430 DATA 1,1,0,64,128,128,128,128,128,128,0

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