Programming by Example

 

A BB4W Compendium

freeman69@gmx.com

IDIC BBC_Owl2 M&P

HopSquash

A compact version of another popular arcade game. Guide frogs to safety on the far side of a road and river.

 

         Z= Left

         X= Right

         K= Forward

         M= Back

 

    This game includes:

 

         Player's frog

         Road and river traffic (collision detection with rectangles)

 

  10 MODE 9:OFF

  20 *REFRESH OFF

  30 VDU 23,23,2;0;0;0;:REM Line thickness=2

  40 VDU 23,35,0,99,99,28,28,28,99,99

  50 MAXOBJ=99

  60 DIM obj{(MAXOBJ) status,row,x,wide}

  70 DIM stack(MAXOBJ),rowdelay(7,1),speed(3,9),bay(5),skull(2)

  80 FOR a=0 TO MAXOBJ:stack(a)=a:NEXT:stackptr=0

  90 FOR a=0 TO 3:FOR b=0 TO 9:READ speed(a,b):NEXT:NEXT

 100 COLOUR 8,128,48,0:COLOUR 9,16,64,0

 110 COLOUR 10,128,128,0:COLOUR 11,0,0,64

 120 lives=0:level=0:score=0:hiscore=0:inplay=0

 130 fx=0:fy=0:fxvel=0:fyvel=0:fc=0:inmotion=FALSE:cd=25*30

 140 TIME=0

 150

 160 REPEAT

 170   T=TIME:CLS:GCOL 0,9

 180   FOR h=0 TO 2:RECTANGLEFILL 0,h*384,1280,128:NEXT

 190   GCOL0,11:RECTANGLEFILL 0,512,1280,256

 200   GCOL 0,10:FOR h=0 TO 4:RECTANGLEFILL 600+(h-2)*200,768,80:NEXT

 210   COLOUR 2:PRINTTAB(2,1);STRING$(lives,"#")

 220   COLOUR 7:PRINTTAB(7,1);"Lvl ";level+1

 230   PRINTTAB(14,1);"Score: ";score

 240   PRINTTAB(27,1);"Hi: ";hiscore

 250   PRINTTAB(37,1);cd DIV 25

 260   REM Frogs in safety

 270   FOR a=0 TO 4

 280     IF bay(a)=1 PROCdrawfrog(a*200+208,768)

 290   NEXT

 300   REM Traffic release timing

 310   FOR r=0 TO 7

 320     IF rowdelay(r,0)>0 THEN

 330       rowdelay(r,0)-=1

 340       IF rowdelay(r,0)=0 rowdelay(r,1)=17-ABS(FNrowspeed(r))

 350     ELSE

 360       IF rowdelay(r,1)>0 THEN

 370         rowdelay(r,1)-=1

 380       ELSE

 390         prob=speed(level MOD 4,8+(r DIV 4))

 400         w=(8+RND(4))*8*(1+(r DIV 4))

 410         IF RND(prob)=1 PROCnewobj(r,w) ELSE rowdelay(r,0)=1

 420       ENDIF

 430     ENDIF

 440   NEXT

 450   REM Traffic control

 460   FOR a=0 TO MAXOBJ

 470     IF obj{(a)}.status THEN

 480       xvel=FNrowspeed(obj{(a)}.row)

 490       obj{(a)}.x+=xvel

 500       dead=FALSE

 510       IF xvel<0 AND obj{(a)}.x<0-obj{(a)}.wide dead=TRUE

 520       IF xvel>0 AND obj{(a)}.x>1280 dead=TRUE

 530       IF dead THEN

 540         stackptr-=1:stack(stackptr)=a:obj{(a)}.status=FALSE

 550       ELSE

 560         IF obj{(a)}.row<4 col=(a MOD 6)+1 ELSE col=8

 570         h=FNobjrowheight(a)

 580         GCOL 0,col:RECTANGLEFILL obj{(a)}.x,h,obj{(a)}.wide,48

 590       ENDIF

 600     ENDIF

 610   NEXT

 620   REM Player control

 630   IF inplay=0 AND TIME>200 THEN

 640     IF score>hiscore hiscore=score

 650     PRINTTAB(10,17);"Press SPACE to play"

 660     IF INKEY$(0)=" " inplay=1

 670   ENDIF

 680   IF inplay=1 score=0:lives=3:inplay=2:level=0:bay()=0

 690   IF inplay=2 fx=640-32:fy=0:cd=25*30:inplay=3

 700   IF inplay=3 THEN

 710     dead=FALSE

 720     IF NOT inmotion THEN

 730       IF INKEY(-98) fxvel=-16:inmotion=TRUE:fc=4

 740       IF INKEY(-67) fxvel=16:inmotion=TRUE:fc=4

 750       IF INKEY(-102) AND NOT inmotion fyvel=-16:inmotion=TRUE:fc=4

 760       IF INKEY(-71) AND NOT inmotion fyvel=16:inmotion=TRUE:fc=4

 770       hit=FNcollided

 780       IF hit>-1 AND hit<4 OR fy>=512 AND hit=-1 dead=TRUE:inplay=2

 790       IF hit<>-1 fx+=FNrowspeed(hit)

 800     ELSE

 810       fx+=fxvel:fy+=fyvel

 820       fc-=1:IF fc=0 fxvel=0:fyvel=0:inmotion=FALSE

 830     ENDIF

 840     IF fx<0 fx=0 ELSE IF fx>1216 fx=1216

 850     IF fy<0 fy=0 ELSE IF fy>=768 fy=768:PROChome

 860     cd-=1:IF cd=0 dead=TRUE:inplay=2

 870     IF dead skull(0)=50:skull(1)=fx:skull(2)=fy:lives-=1

 880     IF lives=0 inplay=0

 890     a=0:h=0:WHILE bay(a)=1 AND a<5:h+=1:a+=1:ENDWHILE

 900     IF h=5 level+=1:bay()=0

 910     IF NOT dead PROCdrawfrog(fx,fy)

 920   ENDIF

 930   REM Skull and crossed bones

 940   IF skull(0)>0 THEN

 950     skull(0)-=1:PROCdrawskull(skull(1),skull(2))

 960   ENDIF

 970  

 980   *REFRESH

 990   *FX21

1000   WAIT 4-(TIME-T)

1010 UNTIL FALSE

1020 END

1030

1040 DATA -2,2,-4,4,-2,2,-4,4,8,3

1050 DATA -3,2,-4,5,-3,3,-5,5,6,4

1060 DATA -4,3,-5,6,-4,4,-6,6,4,5

1070 DATA -5,4,-6,8,-5,5,-7,7,3,6

1080

1090 DEF PROChome

1100 LOCAL a,b,home

1110 a=fx MOD 200:b=(fx DIV 200)-1

1120 inplay=2:home=FALSE

1130 IF a>=0 AND a<32 AND b>=0 AND b<=4 THEN

1140   IF bay(b)=0 bay(b)=1:score+=10:home=TRUE

1150 ENDIF

1160 IF NOT home dead=TRUE

1170 ENDPROC

1180

1190 DEF FNrowspeed(row)

1200 =speed(level MOD 4,row)*2

1210

1220 DEF FNobjrowheight(a)

1230 =8+(1+(obj{(a)}.row DIV 4))*128+obj{(a)}.row*64

1240

1250 DEF PROCnewobj(row,wide)

1260 LOCAL p,x

1270 IF stackptr<MAXOBJ THEN

1280   p=stack(stackptr):stackptr+=1

1290   IF row MOD 2=0 x=1280 ELSE x=-wide

1300   obj{(p)}.status=TRUE:obj{(p)}.row=row

1310   obj{(p)}.x=x:obj{(p)}.wide=wide

1320   rowdelay(row,0)=wide DIV ABS(FNrowspeed(row))

1330 ENDIF

1340 ENDPROC

1350

1360 DEF PROCdrawfrog(x,y)

1370 LOCAL a,b

1380 FOR b=0 TO 1:FOR a=0 TO 1

1390     GCOL0,2:RECTANGLEFILL x+a*44,y+b*44,20

1400     GCOL0,0:RECTANGLE x+a*44,y+b*44,20

1410   NEXT:NEXT

1420 GCOL0,2:RECTANGLEFILL x+12,y+12,40

1430 GCOL0,0:RECTANGLE x+12,y+12,40

1440 ENDPROC

1450

1460 DEF PROCdrawskull(x,y)

1470 GCOL 0,7:VDU 23,23,5;0;0;0;

1480 LINE x,y,x+64,y+40

1490 LINE x,y+40,x+64,y

1500 VDU 23,23,2;0;0;0;

1510 CIRCLEFILL x+34,y+52,20

1520 ENDPROC

1530

1540 DEF FNcollided

1550 LOCAL a,row,x,w,h

1560 row=-1

1570 FOR a=0 TO MAXOBJ

1580   IF obj{(a)}.status THEN

1590     x=obj{(a)}.x:w=obj{(a)}.wide:h=FNobjrowheight(a)

1600     IF fy+64>h AND fy<h+48 AND fx+64>x AND fx<x+w row=obj{(a)}.row

1610   ENDIF

1620 NEXT

1630 =row

HopSquash

HopSquash: Code explained...

 

  50 MAXOBJ=99

  60 DIM obj{(MAXOBJ) status,row,x,wide}

  70 DIM stack(MAXOBJ),rowdelay(7,1),speed(3,9),bay(5),skull(2)

 

Road traffic and logs are held in the 'obj' array. There are 8 lanes ('row') in total. Individual cars and logs can vary in length ('wide') and each has an 'x' position across the window.

The direction and 'speed' of movement depends upon the lane number. This information is defined by DATA lines. Columns 8 & 9 of the 'speed' array control the relative probability of a car or log appearing.

 

 120 lives=0:level=0:score=0:hiscore=0:inplay=0

 130 fx=0:fy=0:fxvel=0:fyvel=0:fc=0:inmotion=FALSE:cd=25*30

 

This game is designed as a simulation, into which, the player is added or removed. Traffic continues to flow while the program is running. Only the probability of a car or log appearing alters with the current level.

'inplay' holds the status of the player within the simulation.

'inmotion' indicates whether the frog is in mid-hop and cannot change direction.

'fc' counts down while the frog is off the ground.

'cd' holds the current value of the total 30 second time limit to reach safety.

 

 170   T=TIME:CLS:GCOL 0,9

 

Because time is an element in this game, we don't reset time to zero at the start of each new frame. Instead, 'T' holds the value of time, recorded at the start of the frame.

 

 310   FOR r=0 TO 7

 320     IF rowdelay(r,0)>0 THEN

 330       rowdelay(r,0)-=1

 340       IF rowdelay(r,0)=0 rowdelay(r,1)=17-ABS(FNrowspeed(r))

 350     ELSE

 360       IF rowdelay(r,1)>0 THEN

 370         rowdelay(r,1)-=1

 380       ELSE

 390         prob=speed(level MOD 4,8+(r DIV 4))

 400         w=(8+RND(4))*8*(1+(r DIV 4))

 410         IF RND(prob)=1 PROCnewobj(r,w) ELSE rowdelay(r,0)=1

 420       ENDIF

 430     ENDIF

 440   NEXT

 

To prevent overlapping objects, a new item of traffic (car or log) can only be added to a lane once the last item added has moved away. The time required to clear the point of entry depends upon the length of the item and its speed.

However, even if the entry area is clear, we may not want to add a new car or log. Lower levels have fewer cars, but more logs; the traffic also moves more slowly.

Line 340 sets a second delay, calculated from the speed of the lane: the faster the lane, the smaller the delay. Once this delay expires, the program uses the probability of an item of traffic appearing (for a given level) to determine if a car or log will appear. If not, then the delay is reset.

 

 510       IF xvel<0 AND obj{(a)}.x<0-obj{(a)}.wide dead=TRUE

 520       IF xvel>0 AND obj{(a)}.x>1280 dead=TRUE

 

Cars and logs are removed from the 'obj' array once they have cleared the far side of the window.

 

 630   IF inplay=0 AND TIME>200 THEN

 640     IF score>hiscore hiscore=score

 650     PRINTTAB(10,17);"Press SPACE to play"

 660     IF INKEY$(0)=" " inplay=1

 670   ENDIF

 680   IF inplay=1 score=0:lives=3:inplay=2:level=0:bay()=0

 690   IF inplay=2 fx=640-32:fy=0:cd=25*30:inplay=3

 

As mentioned above, 'inplay' holds the status of the player:

0 = Awaiting the start of a new game

1 = Starting a new game

2 = Starting a new life

3 = Playing game

 

 770       hit=FNcollided

 780       IF hit>-1 AND hit<4 OR fy>=512 AND hit=-1 dead=TRUE:inplay=2

 790       IF hit<>-1 fx+=FNrowspeed(hit)

 

The frog can collide with cars and logs, but the result is different for each. While a collision with a car is fatal, the frog must hop onto logs to survive the river crossing, with the additional factor of moving with the log when aboard.

 

 840     IF fx<0 fx=0 ELSE IF fx>1216 fx=1216

 850     IF fy<0 fy=0 ELSE IF fy>=768 fy=768:PROChome

 

The frog is prevented from moving outside the window border.

 

 890     a=0:h=0:WHILE bay(a)=1 AND a<5:h+=1:a+=1:ENDWHILE

 900     IF h=5 level+=1:bay()=0

 

When all 5 bays contain a frog, the level increases.

 

 940   IF skull(0)>0 THEN

 950     skull(0)-=1:PROCdrawskull(skull(1),skull(2))

 960   ENDIF

 

Upon the death of the frog, a skull and crossed bones symbol is displayed for a limited time.

 

1090 DEF PROChome

 

When the frog reaches the far side, we must test to determine if it landed within an unoccupied bay. If not, then the frog is dead. Either way, a new frog will start a new journey.

 

1250 DEF PROCnewobj(row,wide)

 

This routine adds a new item of traffic to the 'obj' array, as long as there is space in the array. A delay for the row is initiated to prevent a new item being added before the current one has cleared the point of entry.

 

1360 DEF PROCdrawfrog(x,y)

1460 DEF PROCdrawskull(x,y)

 

These two routines draw relevant graphics.

 

1540 DEF FNcollided

1550 LOCAL a,row,x,w,h

1560 row=-1

1570 FOR a=0 TO MAXOBJ

1580   IF obj{(a)}.status THEN

1590     x=obj{(a)}.x:w=obj{(a)}.wide:h=FNobjrowheight(a)

1600     IF fy+64>h AND fy<h+48 AND fx+64>x AND fx<x+w row=obj{(a)}.row

1610   ENDIF

1620 NEXT

1630 =row

 

This function returns the row number of the item of traffic the frog has collided with, or -1 if no collision has occurred. The test determines if the square frog overlaps a rectangular item of traffic (the latter of of fixed height=48 and variable length).

It is possible to increase the efficiency of this routine by exiting as soon as a collision is detected.

Arrow black large Arrow black large