See also: part 1, part 2, part 3, part 4, unrelated, and part 5.
In part 1, I showed a simple but slow way to recreate a classic CoCo game startup screen with color blocks moving around the screen. I recall many early CoCo games had startup screens similar to this, though fancier. The assembly language games would rotate all the blocks around the screen, rather than just moving four blocks like my BASIC demo does. For instance, Steve Bjork‘s port of Clowns and Balloons:
You can check it out in videos on YouTube, or play it in a web browser via the wonderful JS Mocha CoCo emulator.
My BASIC attract screen does not attempt to recreate that one, but is more of an homage to the style of attract screens we had in those early years.
My initial version clocked in at about 30 lines, and I suggested ways to make it smaller, such as using arrays to store screen locations rather than individual variables. Arrays make things smaller, but are slower. i.e., if you wanted to track four ghosts on the screen for a Pac-Man game, you could have variables like G1, G2, G3 and G4 and then have a block of code that handled each one individually. Or, you could have an array such as DIM G(3) and access the four ghost locations using G(0), G(1), G(2) and G(3). This allows handling the ghosts in a FOR/NEXT loop instead of four individual blocks of code using separate variables.
Here is a verbose example of randomly moving around four “ghosts”:
10 ' WANDERING.BAS 20 CLS0 30 G1=1024:G2=1055:G3=1504:G4=1535 40 C1=191:C2=239:C3=223:C4=255 50 ' DISPLAY GHOSTS 60 POKE G1,C1:POKE G2,C2:POKE G3,C3:POKE G4,C4 70 ' RANDOM MOVE G1 80 ON RND(4) GOTO 90,100,110,120 90 NL=G1+1:GOTO 130 100 NL=G1-1:GOTO 130 110 NL=G1-32:GOTO 130 120 NL=G1+32 130 IF NL<1024 THEN 180 140 IF NL>1535 THEN 180 150 ' ERASE G1 AND UPDATE LOCATION 160 POKE G1,128:POKE NL,C1:G1=NL 170 ' RANDOM MOVE G2 180 ON RND(4) GOTO 190,200,210,220 190 NL=G2+1:GOTO 230 200 NL=G2-1:GOTO 230 210 NL=G2-32:GOTO 230 220 NL=G2+32 230 IF NL<1024 THEN 280 240 IF NL>1535 THEN 280 250 ' ERASE G2 AND UPDATE LOCATION 260 POKE G2,128:POKE NL,C2:G2=NL 270 ' RANDOM MOVE G3 280 ON RND(4) GOTO 290,300,310,320 290 NL=G3+1:GOTO 330 300 NL=G3-1:GOTO 330 310 NL=G3-32:GOTO 330 320 NL=G3+32 330 IF NL<1024 THEN 380 340 IF NL>1535 THEN 380 350 ' ERASE G4 AND UPDATE LOCATION 360 POKE G3,128:POKE NL,C3:G3=NL 370 ' RANDOM MOVE G4 380 ON RND(4) GOTO 390,400,410,420 390 NL=G4+1:GOTO 430 400 NL=G4-1:GOTO 430 410 NL=G4-32:GOTO 430 420 NL=G4+32 430 IF NL<1024 THEN 470 440 IF NL>1535 THEN 470 450 ' ERASE G4 AND UPDATE LOCATIOn 460 POKE G4,128:POKE NL,C4:G4=NL 470 GOTO 60
And here is that same program, converted to use arrays for the four ghost locations, four ghost colors, and four directions:
10 ' WANDERING2.BAS
20 CLS0
30 G(0)=1024:G(1)=1055:G(2)=1504:G(3)=1535
40 C(0)=191:C(1)=239:C(2)=223:C(3)=255
45 D(0)=1:D(1)=-1:D(2)=-32:D(3)=32
50 ' DISPLAY GHOSTS
60 FOR I=0 TO 3:POKE G(I),C(I)
70 ' RANDOM MOVE G(I)
80 NL=G(I)+D(RND(4)-1)
130 IF NL<1024 THEN 170
140 IF NL>1535 THEN 170
150 ' ERASE G(I) AND UPDATE LOCATION
160 POKE G(I),128:POKE NL,C(I):G(I)=NL
170 NEXT
470 GOTO 60
I tried to keep common line numbers where I could. 47 lines of code down to 15.
And, now that it is an array, it’s easy to make it handle as many ghosts as you want. By adding one more element to the array, and changing the FOR/NEXT loop to count 0-4 instead of 0-3, we get an extra ghost:
10 ' WANDERING3.BAS
20 CLS0
30 G(0)=1024:G(1)=1055:G(2)=1504:G(3)=1535:G(4)=1263
40 C(0)=191:C(1)=239:C(2)=223:C(3)=255:C(4)=143
45 D(0)=1:D(1)=-1:D(2)=-32:D(3)=32
50 ' DISPLAY GHOSTS
60 FOR I=0 TO 4:POKE G(I),C(I)
70 ' RANDOM MOVE G(I)
80 NL=G(I)+D(RND(4)-1)
130 IF NL<1024 THEN 170
140 IF NL>1535 THEN 170
150 ' ERASE G(I) AND UPDATE LOCATION
160 POKE G(I),128:POKE NL,C(I):G(I)=NL
170 NEXT
470 GOTO 60
Arrays are great for reducing code size, and making it so one routine can handle multiple instances of something (locations, colors, etc.).
But, it is slower. Looking up X(3) is slower than looking up X3 since looking up an array has to first look up the variable, and then index in to it to find the entry.
Here is the attract code, converted to use arrays for the block positions and movement directions. As you can see, I’m basically handling the blocks like I did the ghosts above — as objects that can be moved around the screen. Instead of making their movement random, they follow a pattern around the outline of the screen. Instead of having a set color, they just cycle through the seven available non-black VDG colors:
10 ' ATTRACT2.BAS
20 L(0)=1024:L(1)=1024+23:L(2)=1535:L(3)=1535-23
30 Z=143
40 CL(0)=1024:CD(0)=1
50 CL(1)=1055:CD(1)=32
60 CL(2)=1535:CD(2)=-1
70 CL(3)=1504:CD(3)=-32
80 CLS 0:PRINT @268,"ATTRACT!";
90 LD(0)=1:LD(1)=1:LD(2)=-1:LD(3)=-1
100 FOR I=0 TO 3:POKE L(I),Z:NEXT
110 Z=Z+16:IF Z>255 THEN Z=143
120 FOR I=0 TO 3:L(I)=L(I)+LD(I):NEXT
130 FOR L=0 TO 3
140 FOR C=0 TO 3
150 IF L(L)=CL(C) THEN LD(L)=CD(C)
160 NEXT
170 NEXT
180 GOTO 100
30 lines of the originally down to 18 by using arrays.
When time isn’t as important as code size (or convenience), arrays are a great thing.
I have two more iterations of this attract screen to share, so I’ll end with…
To be continue…
Very nice!
The fight game I´m making does not use arrays for the speed impact is enormous. Code size increases but since each enemy is more or less unique, it is worth, otherwise I would have to add too many exceptions to the for/next array… not worth on a one on one fight style game.
Hi, Erico! I have a few more weekly posts to ramble on about, then I plan to work up my “game” into a full program and see how fast I can make it.