Programming by Example

 

A BB4W Compendium

freeman69@gmx.com

IDIC BBC_Owl2 M&P

Invaders From Space

Classic arcade games provide an engaging format for demonstrating programming techniques, including the practical application of mathematics.

 

In general, computers require input, either from a user and/or from data files and tables. Various routines process data for output, usually to some form of display.

 

         Z = Move base left

         X = Move base right

         Enter = Fire

 

    This game includes:

 

         The player's base

         The player's laser bullet

         70 advancing aliens

         Multiple alien bombs

 

  10 MODE 9:OFF

  20 ORIGIN 640,0

  30 DIM alien(69,5),bomb(9,4)

  40

  50 VDU 23,224,60,78,78,60,126,255,255,126:REM Alien look left

  60 VDU 23,225,60,114,114,60,126,255,255,126:REM Alien look right

  70 VDU 23,226,1,65,109,127,255,255,238,68:REM Base left half

  80 VDU 23,227,128,130,182,254,255,255,119,34:REM Base right half

  90 VDU 23,230,192,192,192,192,192,192,0,0:REM Bullet

 100 VDU 23,231,60,126,126,60,126,255,255,126:REM Alien solid

 110 VDU 23,232,120,252,252,252,252,252,252,120:REM Bullet hole

 120 VDU 23,233,252,252,252,252,252,252,0,0:REM Debris

 130 VDU 23,234,96,240,240,96,0,0,0,0:REM Bomb

 140

 150 hiscore=0

 160 REPEAT

 170   lives=3:score=0

 180   REPEAT

 190     restart=FALSE

 200     playeralive=TRUE

 210     firing=FALSE

 220     aliensalive=0

 230     funeral=0

 240     bombptr$="0123"

 250     FOR b=0 TO 9:bomb(b,0)=FALSE:NEXT

 260     CLS

 270     PRINT;"Lives ";lives TAB(10);"Score ";score TAB(24);"Hi-Score ";hiscore

 280     basex=-32:GCOL 0,7:MOVE basex,40:VDU 5,226,227,4:REM player's start position

 290     GCOL 0,3:FOR b=0 TO 3:PROCbarrier((b-1.5)*320,256):NEXT

 300     REPEAT

 310       TIME=0

 320       IF aliensalive=0 PROCnewaliens

 330       PROCmovesomealiens(aliencolumn):aliencolumn+=1

 340       IF aliencolumn=10 THEN

 350         aliencolumn=0

 360         IF allchange wavedirection*=-1:dropcount+=1:allchange=FALSE

 370       ENDIF

 380       IF playeralive PROCdroppingbomb:PROCplayer ELSE PROCexplode

 390       PROCbullet

 400       WAIT 4-TIME

 410       *FX21

 420     UNTIL restart

 430     lives-=1

 440   UNTIL lives=0

 450   PRINTTAB(7,15);"Press SPACE to play again"

 460   REPEATUNTILGET=32

 470   IF score>hiscore hiscore=score

 480 UNTIL FALSE

 490 END

 500

 510 DEF PROCbarrier(x,y)

 520 RECTANGLEFILL x-80,y-64,160,120

 530 ENDPROC

 540

 550 DEF PROCnewaliens

 560 LOCAL gap,offsetx,alf,x,y:REM Initialise wave of aliens

 570 wavedirection=-16:aliensalive=70:aliencolumn=0:dropcount=0:allchange=FALSE

 580 gap=64:offsetx=5*gap

 590 alf=0

 600 FOR y=0 TO 6

 610   FOR x=0 TO 9

 620     alien(alf,0)=TRUE:REM alive

 630     alien(alf,1)=y+1:REM colour

 640     alien(alf,2)=x*gap-offsetx:REM x

 650     alien(alf,3)=y*gap+512:REM y

 660     alien(alf,4)=224+x MOD 2:REM graphic

 670     alien(alf,5)=0:REM dropcount

 680     WAIT 1

 690     GCOL 0,alien(alf,1):PROCdrawalien(alf,alien(alf,4))

 700     alf+=1

 710   NEXT

 720 NEXT

 730 ENDPROC

 740

 750 DEF PROCdrawalien(alf,gfx)

 760 MOVE alien(alf,2),alien(alf,3):VDU 5,gfx,4

 770 ENDPROC

 780

 790 DEF PROCmovesomealiens(c)

 800 LOCAL a,b:REM Animation of aliens

 810 FOR a=0 TO 69

 820   IF a MOD 10=c AND alien(a,0) THEN

 830     GCOL 0,0:PROCdrawalien(a,231)

 840     alien(a,4)EOR=1

 850     alien(a,2)+=wavedirection

 860     IF alien(a,2)<-600 OR alien(a,2)>568 allchange=TRUE

 870     IF alien(a,5)<dropcount alien(a,5)+=1:alien(a,3)-=32

 880     GCOL 0,alien(a,1):PROCdrawalien(a,alien(a,4))

 890     IF alien(a,3)<=32 playeralive=FALSE

 900     IF playeralive AND RND(10)=1 AND bombptr$<>"" THEN

 910       b=VAL(RIGHT$(bombptr$,1)):bombptr$=LEFT$(bombptr$,LEN(bombptr$)-1)

 920       bomb(b,0)=TRUE:REM bomb is active

 930       bomb(b,1)=alien(a,2)+8:REM bomb x

 940       bomb(b,2)=alien(a,3)-32:REM bomb y

 950       bomb(b,4)=RND(2)*12:REM bomb velocity

 960     ENDIF

 970   ENDIF

 980 NEXT

 990 ENDPROC

1000

1010 DEF PROCplayer

1020 LOCAL moving,xd:REM Animation of player's base

1030 moving=FALSE

1040 IF INKEY(-98) AND basex>-600 moving=TRUE:xd=-12

1050 IF INKEY(-67) AND basex<536 moving=TRUE:xd=12

1060 IF moving THEN

1070   GCOL 0,0:MOVE basex,40:VDU 5,226,227,4

1080   basex+=xd

1090   GCOL 0,7:MOVE basex,40:VDU 5,226,227,4

1100 ENDIF

1110 IF INKEY(-74) AND NOT firing THEN

1120   bulletx=basex+28:bullety=64:firing=TRUE

1130 ENDIF

1140 ENDPROC

1150

1160 DEF PROCbullet

1170 REM Animation of player's bullet

1180 IF firing THEN

1190   GCOL 0,0:MOVE bulletx,bullety:VDU 5,230,4

1200   bullety+=24

1210   IF FNimpacted OR bullety>960 THEN

1220     GCOL 0,0:MOVE bulletx-8,bullety:VDU 5,232,4

1230     IF bullety<928 PROCtestaliens

1240     firing=FALSE

1250   ELSE

1260     GCOL 0,1:MOVE bulletx,bullety:VDU 5,230,4

1270   ENDIF

1280 ENDIF

1290 ENDPROC

1300

1310 DEF FNimpacted

1320 LOCAL y:REM Player's bullet impacted anything?

1330 hit=FALSE:y=0

1340 WHILE NOT hit AND y<6

1350   IF POINT(bulletx,bullety-y*4)<>0 hit=TRUE

1360   y+=1

1370 ENDWHILE

1380 =hit

1390

1400 DEF PROCtestaliens

1410 LOCAL hit,a:REM Player's bullet hit an alien?

1420 hit=FALSE:a=0

1430 REPEAT

1440   IF alien(a,0) THEN

1450     IF bulletx>=alien(a,2) AND bulletx<alien(a,2)+32 THEN

1460       IF bullety>alien(a,3)-32 AND bullety<alien(a,3)+24 THEN

1470         alien(a,0)=FALSE:aliensalive-=1:hit=TRUE

1480         score+=10:IF aliensalive=0 score+=400

1490         PRINTTAB(16,0);score

1500         GCOL 0,0:PROCdrawalien(a,231)

1510       ENDIF

1520     ENDIF

1530   ENDIF

1540   a+=1

1550 UNTIL hit OR a>69

1560 ENDPROC

1570

1580 DEF PROCdroppingbomb

1590 LOCAL a,bombdead,x,y:REM Alien bombs

1600 FOR a=0 TO 9

1610   bombdead=FALSE

1620   IF bomb(a,0) THEN

1630     GCOL 0,0:MOVE bomb(a,1),bomb(a,2):VDU 5,234,4

1640     bomb(a,2)-=bomb(a,4)

1650     x=bomb(a,1):y=bomb(a,2)

1660     IF y<16 OR y<316 AND y>196 AND POINT(x,y)=3 THEN

1670       bombdead=TRUE:GCOL 0,0:MOVE x,y+2/3*bomb(a,4):VDU 5,234,4

1680     ELSE

1690       IF y<56 AND x>basex-12 AND x<basex+64 playeralive=FALSE:bombdead=TRUE

1700     ENDIF

1710     IF bombdead THEN

1720       bomb(a,0)=FALSE:bombptr$+=STR$(a)

1730     ELSE

1740       GCOL 0,5:MOVE bomb(a,1),bomb(a,2):VDU 5,234,4

1750     ENDIF

1760   ENDIF

1770 NEXT

1780 ENDPROC

1790

1800 DEF PROCexplode

1810 LOCAL a:REM Destruction of player's base

1820 IF funeral=0 THEN

1830   FOR a=0 TO 9

1840     bomb(a,1)=basex+16:bomb(a,2)=40

1850     bomb(a,3)=RND(128)-64:bomb(a,4)=RND(64)

1860   NEXT

1870 ENDIF

1880 FOR a=0 TO 9

1890   GCOL 0,0:MOVE bomb(a,1),bomb(a,2):VDU 5,233,4

1900   bomb(a,1)+=bomb(a,3)

1910   bomb(a,2)+=bomb(a,4)

1920   GCOL 0,7:MOVE bomb(a,1),bomb(a,2):VDU 5,233,4

1930 NEXT

1940 IF funeral=50 restart=TRUE

1950 funeral+=1

1960 ENDPROC

Invaders From Space: Code explained...

 

  10 MODE 9:OFF

  20 ORIGIN 640,0

  30 DIM alien(69,5),bomb(9,4)

 

We're using MODE 9 again and shifting the graphics origin to the horizontal centre of the window, but leaving the vertical origin at the bottom. This arrangement is handy because the game graphics begin with a degree of vertical symmetry.

This game requires two tables. The first holds information on each alien. The second holds details of any bombs they drop.

 

  50 VDU 23,224,60,78,78,60,126,255,255,126:REM Alien look left

  60 VDU 23,225,60,114,114,60,126,255,255,126:REM Alien look right

  70 VDU 23,226,1,65,109,127,255,255,238,68:REM Base left half

  80 VDU 23,227,128,130,182,254,255,255,119,34:REM Base right half

  90 VDU 23,230,192,192,192,192,192,192,0,0:REM Bullet

 100 VDU 23,231,60,126,126,60,126,255,255,126:REM Alien solid

 110 VDU 23,232,120,252,252,252,252,252,252,120:REM Bullet hole

 120 VDU 23,233,252,252,252,252,252,252,0,0:REM Debris

 130 VDU 23,234,96,240,240,96,0,0,0,0:REM Bomb

 

Note that any of these VDU 23 commands can be replaced with your own design of graphics. We're using characters 224, 225, 226, 227, 230, 231, 232, 233 & 234.

 

 150 hiscore=0

 160 REPEAT

 170   lives=3:score=0

 

This is another program that doesn't self-terminate. The condition of the related UNTIL command is never met. This is the outer-loop allowing a new game to be started once the current game has finished.

'hiscore' is the variable used to store the player's highest score.

'score' will hold the current score for the current game.

 

 180   REPEAT

 190     restart=FALSE

 200     playeralive=TRUE

 210     firing=FALSE

 220     aliensalive=0

 230     funeral=0

 240     bombptr$="0123"

 

This is the middle-loop, cycling once per life of the player.

'restart' will be used to indicate that a new life needs to be started.

'playeralive' indicates whether the player's base is active or has been destroyed. When the base has been destroyed the game animation doesn't reset immediately. Before the player obtains another base, we show the old base exploding. While the explosion is being animated, the player cannot interact with the game.

'firing' indicates the existence of a laser bullet. The game is designed to allow one active bullet only. This limit introduces a degree of skill to the game.

'aliensalive' keeps track of the number of aliens still alive.

'funeral' is used as a counter when animating the base explosion.

'bombptr$' limits the number of alien bombs active simultaneously. Change this string to increase or decrease the number of bombs, up to a maximum of 10 e.g. “0123456789”

 

 250     FOR b=0 TO 9:bomb(b,0)=FALSE:NEXT

 

The first element in the bomb array is set to FALSE (for each bomb). This deactivates any bombs left active from a previous game.

 

 260     CLS

 270     PRINT;"Lives ";lives TAB(10);"Score ";score TAB(24);"Hi-Score ";hiscore

 280     basex=-32:GCOL 0,7:MOVE basex,40:VDU 5,226,227,4:REM player's start position

 290     GCOL 0,3:FOR b=0 TO 3:PROCbarrier((b-1.5)*320,256):NEXT

 

On the commencement of each new life or game, we clear the screen of any leftover graphics.

Line 280 draws the player's base.

Line 290 calls a procedure 4 times to draw 4 yellow barriers. Note that PROCbarrier includes brackets containing values. This is an example of parameters being passed to a procedure. See line 510. The parameters are the x and y co-ordinates of the barrier's position.

 

 300     REPEAT

 310       TIME=0

 

This is the inner-loop, cycling once per animation frame. We use the computer's internal clock to time how long it takes to draw each animation frame.

 

 320       IF aliensalive=0 PROCnewaliens

 

When the player has destroyed all of the aliens, this triggers the creation of a new wave.

 

 330       PROCmovesomealiens(aliencolumn):aliencolumn+=1

 340       IF aliencolumn=10 THEN

 350         aliencolumn=0

 360         IF allchange wavedirection*=-1:dropcount+=1:allchange=FALSE

 370       ENDIF

 

PROCmovesomealiens() moves one column of aliens per animation frame. This method minimises the total graphics needing to be redrawn each animation cycle. A secondary effect is to limit the speed of the alien advance.

'aliencolumn' counts from zero to 9, incrementing once per animation frame.

 

When every alien in the wave has been moved, we check for the edge of the display. If any alien has reached one side of the window, or another, then the whole wave changes direction, as well as dropping down a line.

 

 380       IF playeralive PROCdroppingbomb:PROCplayer ELSE PROCexplode

 

If the player is alive then we call the PROCplayer procedure for user input. We're also cheating slightly because we're going to use the alien bomb array to process the destruction of the player's base. This means that when the player is alive we want to process any active alien bombs, but if the player is dead then we process the explosion of the base instead.

 

 390       PROCbullet

 

The player's laser bullet is processed independently of the player.

 

 400       WAIT 4-TIME

 410       *FX21

 420     UNTIL restart

 

Line 400 limits the speed of the game to 25 animation frames per second (i.e. 4 one hundredths of a second per frame).

The end of the inner-loop. This ends with the end of a player's life.

 

 430     lives-=1

 440   UNTIL lives=0

 

Line 430 reduces the player's lives by one.

The end of the middle-loop. This ends when the player has run out of lives.

 

 450   PRINTTAB(7,15);"Press SPACE to play again"

 460   REPEATUNTILGET=32

 470   IF score>hiscore hiscore=score

 480 UNTIL FALSE

 490 END

 

The end of the outer-loop and the end of the main part of the program.

 

 510 DEF PROCbarrier(x,y)

 520 RECTANGLEFILL x-80,y-64,160,120

 530 ENDPROC

 

Recall that PROCbarrier is called 4 times, to draw 4 yellow rectangles that act as partial barriers to alien bombs and laser bullets.

 

 550 DEF PROCnewaliens

 560 LOCAL gap,offsetx,alf,x,y:REM Initialise wave of aliens

 570 wavedirection=-16:aliensalive=70:aliencolumn=0:dropcount=0:allchange=FALSE

 

PROCnewaliens creates a new wave of 70 aliens in 10 columns of 7.

 

The LOCAL command instructs BB4W to treat the listed variables as 'local' to this procedure. This means that these variables don't exist as far as the main part of the program is concerned. It is generally good practice to use local variables. It allows the reuse of variable names in different procedures for different purposes. You will note that many variables are given useful names like 'aliensalive', but often we need a variable for a simple loop, using 'a', 'b', 'x', 'y' etc for convenience. Problems arise when the same variable is used in more than one place in a conflicting manner. Making variables 'local' to procedures can reduce the risk of creating such conflicts.

 

'wavedirection' controls the direction of alien movement and is reversed when any alien reaches one side of the window or another.

'dropcount' and 'allchange' are used to synchronise alien movement downwards.

 

 580 gap=64:offsetx=5*gap

 

'gap' and 'offsetx' control the spacing of the alien wave.

 

 590 alf=0

 600 FOR y=0 TO 6

 610   FOR x=0 TO 9

 620     alien(alf,0)=TRUE:REM alive

 630     alien(alf,1)=y+1:REM colour

 640     alien(alf,2)=x*gap-offsetx:REM x

 650     alien(alf,3)=y*gap+512:REM y

 660     alien(alf,4)=224+x MOD 2:REM graphic

 670     alien(alf,5)=0:REM dropcount

 680     WAIT 1

 690     GCOL 0,alien(alf,1):PROCdrawalien(alf,alien(alf,4))

 700     alf+=1

 710   NEXT

 720 NEXT

 730 ENDPROC

 

The remainder of the routine initialises individual alien variables and draws each alien. Each column of the 'alien' array holds a specific value e.g. the colour of the alien is related to the row. Array columns 2 and 3 hold the position (x,y co-ordinates) of the alien.

Line 690 includes a call to PROCdrawalien. This is another procedure that requires parameters. Note that the second parameter is an array value, passed to the equivalent PROCdrawalien variable called 'gfx' on line 750. This is the user-defined character to be drawn.

 

 750 DEF PROCdrawalien(alf,gfx)

 760 MOVE alien(alf,2),alien(alf,3):VDU 5,gfx,4

 770 ENDPROC

 

PROCdrawalien draws the graphics for one alien only. Note that the colour of the alien is set elsewhere. If drawn in black then the image of the alien is effectively deleted from the window.

 

 790 DEF PROCmovesomealiens(c)

 800 LOCAL a,b:REM Animation of aliens

 810 FOR a=0 TO 69

 820   IF a MOD 10=c AND alien(a,0) THEN

 

As mentioned above, we process one column of aliens per animation frame. The FOR... NEXT loop and the IF statement within this procedure select the relevant aliens for processing.

 

 830     GCOL 0,0:PROCdrawalien(a,231)

 

Deletes the current alien image from the window by drawing an image in black.

 

 840     alien(a,4)EOR=1

 

The 8 x 8 characters, used for animating an alien, face to the left and to the right. This line 'toggles' or 'flip-flops' between the two directions.

 

 850     alien(a,2)+=wavedirection

 

Moves one alien in the current direction of the wave.

 

 860     IF alien(a,2)<-600 OR alien(a,2)>568 allchange=TRUE

 

Tests to see if this alien has reached the edge of the window.

 

 870     IF alien(a,5)<dropcount alien(a,5)+=1:alien(a,3)-=32

 

Does this alien have to drop down a line because another alien has already reached the edge of the window?

 

 880     GCOL 0,alien(a,1):PROCdrawalien(a,alien(a,4))

 

Draws the new image of the alien.

 

 890     IF alien(a,3)<=32 playeralive=FALSE

 

Player loses when an alien touches the ground.

 

 900     IF playeralive AND RND(10)=1 AND bombptr$<>"" THEN

 

This section processes a possible alien bomb-release, but only if the player is still alive.

RND(10) returns a random value between 1 and 10, inclusive.

If 'bombptr$' is empty then this indicates that there are no free spaces in the 'bomb' array.

 

 910       b=VAL(RIGHT$(bombptr$,1)):bombptr$=LEFT$(bombptr$,LEN(bombptr$)-1)

 

This use of 'bombptr$' is one method to control and limit the number of alien bombs. When the program is run you will notice that alien bombs have varying life spans. One bomb may exist for longer than another, depending on how fast it drops and whether it hits a barrier before reaching the ground or the player.

So whenever we want an alien to drop a bomb, we have to check that we can accommodate the alien's request. One way is to loop through the 'bomb' array, looking for spaces i.e. an empty bomb row. Our bomb array is very small, having only 10 spaces available, so any method would be okay. However, some programs may control hundreds or even thousands of objects, in which case it would be extremely inefficient to read though the entire list. One alternative method is to create a 'stack' of 'pointers', just like the 'bombptr$' string. The stack is a separate array (or string) that holds the number of every empty array row. Whenever we need to find an empty space we simply take the next number off the top of the stack. When the object is no longer needed then we then return its 'pointer' (row number) to the stack.

 

VAL(RIGHT$(bombptr$,1)) returns a numeric value, equal to the rightmost digit in the bombptr$ string.

bombptr$=LEFT$(bombptr$,LEN(bomptr$)-1) removes the rightmost digit from bombptr$.

 

 920       bomb(b,0)=TRUE:REM bomb is active

 930       bomb(b,1)=alien(a,2)+8:REM bomb x

 940       bomb(b,2)=alien(a,3)-32:REM bomb y

 950       bomb(b,4)=RND(2)*12:REM bomb velocity

 960     ENDIF

 970   ENDIF

 980 NEXT

 990 ENDPROC

 

Just like the alien array, the bomb array holds the details of every bomb.

RND(2)*12 randomly returns the value 12 or 24. This will be the speed that the bomb drops.

(Note that RND(1) returns a fractional value between zero and 1.)

 

1010 DEF PROCplayer

1020 LOCAL moving,xd:REM Animation of player's base

1030 moving=FALSE

 

Our method of animation is very simple and we only want to delete a particular graphic if the object is being moved. If it hasn't moved then there's no point in deleting the image and redrawing it.

 

1040 IF INKEY(-98) AND basex>-600 moving=TRUE:xd=-12

1050 IF INKEY(-67) AND basex<536 moving=TRUE:xd=12

 

INKEY(-98) tests the status of the 'Z' key and returns TRUE if currently depressed. This method of testing keyboard input is preferable over others when quick responses are required.

 

1060 IF moving THEN

1070   GCOL 0,0:MOVE basex,40:VDU 5,226,227,4

1080   basex+=xd

1090   GCOL 0,7:MOVE basex,40:VDU 5,226,227,4

1100 ENDIF

 

If the player has moved the base left or right, then the program deletes the old image (at the old co-ordinates), updates the position of the base and redraws the graphics.

'xd' can hold a positive or negative value. Adding 'xd' to 'basex' will increase or decrease the value of 'basex'.

VDU 5,226,227,4 is an instruction to draw text at the graphics cursor and print character 226 immediately followed by character 227. VDU 4 returns text positioning to the control of the text cursor.

 

1110 IF INKEY(-74) AND NOT firing THEN

1120   bulletx=basex+28:bullety=64:firing=TRUE

1130 ENDIF

1140 ENDPROC

 

Firing a laser bullet can only occur if a bullet is not already active.

'bulletx', 'bullety' and 'firing' hold the details of the current laser bullet.

 

1160 DEF PROCbullet

1170 REM Animation of player's bullet

1180 IF firing THEN

1190   GCOL 0,0:MOVE bulletx,bullety:VDU 5,230,4

1200   bullety+=24

 

A Laser bullet is always moving, so we always want to update its position and redraw the bullet, deleting the old image first.

 

1210   IF FNimpacted OR bullety>960 THEN

 

FNimpacted is the first appearance of a 'function'. Functions are almost identical to procedures, except they always return a single value. In this instance FNimpacted returns either TRUE or FALSE depending on a specific test.

Many computer languages do not discriminate between procedures and functions.

 

1220     GCOL 0,0:MOVE bulletx-8,bullety:VDU 5,232,4

 

This line draws a bullet hole. In the event a bullet hits one of the 4 barriers, it will cause significant damage to the relevant barrier.

 

1230     IF bullety<928 PROCtestaliens

1240     firing=FALSE

1250   ELSE

1260     GCOL 0,1:MOVE bulletx,bullety:VDU 5,230,4

1270   ENDIF

1280 ENDIF

1290 ENDPROC

 

Below a specific altitude, the bullet will be tested for collision with an alien, but only if the bullet is found to have hit 'something' (see FNimpacted).

If no impact was detected then the routine draws the bullet in its updated position.

 

1310 DEF FNimpacted

1320 LOCAL y:REM Player's bullet impacted anything?

1330 hit=FALSE:y=0

1340 WHILE NOT hit AND y<6

1350   IF POINT(bulletx,bullety-y*4)<>0 hit=TRUE

1360   y+=1

1370 ENDWHILE

1380 =hit

 

FNimpacted looks at the next 6 pixels in the immediate path of the bullet. If any non-black pixels are detected then the function returns a value of TRUE.

POINT(x,y) returns the colour of a pixel at co-ordinates x,y

 

WHILE... ENDWHILE is another form of loop structure. A WHILE loop will only execute if its defining criteria are met. In this instance the loop executes until 6 pixels are tested or a non-black colour is detected.

This specific example could be replaced by REPEAT... UNTIL hit OR y=6

 

Note the '=' at then end of the function. This is the main difference between a function and a procedure.

 

1400 DEF PROCtestaliens

1410 LOCAL hit,a:REM Player's bullet hit an alien?

1420 hit=FALSE:a=0

1430 REPEAT

1440   IF alien(a,0) THEN

1450     IF bulletx>=alien(a,2) AND bulletx<alien(a,2)+32 THEN

1460       IF bullety>alien(a,3)-32 AND bullety<alien(a,3)+24 THEN

 

PROCtestaliens is only called when the program thinks a laser bullet may have collided with an alien.

This routine tests every alien, checking that the alien is still active/alive.

Next we check to see if the bullet falls within the rectangular area of the alien, i.e. between its top and bottom and between its left and right sides.

 

1470         alien(a,0)=FALSE:aliensalive-=1:hit=TRUE

1480         score+=10:IF aliensalive=0 score+=400

1490         PRINTTAB(16,0);score

1500         GCOL 0,0:PROCdrawalien(a,231)

1510       ENDIF

1520     ENDIF

1530   ENDIF

1540   a+=1

1550 UNTIL hit OR a>69

1560 ENDPROC

 

If a collision is detected then the alien is deactivated, and its image within the window deleted. We also increase the player's score, with a bonus for the destruction of an entire wave.

 

1580 DEF PROCdroppingbomb

1590 LOCAL a,bombdead,x,y:REM Alien bombs

1600 FOR a=0 TO 9

 

PROCdroppingbomb processes the movement of up to 10 bombs currently in free-fall.

 

1610   bombdead=FALSE

1620   IF bomb(a,0) THEN

1630     GCOL 0,0:MOVE bomb(a,1),bomb(a,2):VDU 5,234,4

1640     bomb(a,2)-=bomb(a,4)

 

Just like laser bullets, bombs are always in motion and require constant redrawing. While laser bullets move upwards at a fixed rate, bombs can drop at different speeds.

 

1650     x=bomb(a,1):y=bomb(a,2)

 

The use of variables 'x' and 'y' in this instance is for convenience only, because it makes the code easier to read than repeated references to bomb(a,1) and bomb(a,2).

 

1660     IF y<16 OR y<316 AND y>196 AND POINT(x,y)=3 THEN

 

Note the complexity of this IF statement. The statement will be TRUE if y is less than 16. It will also be TRUE if y is less than 316 AND y is greater than 196 AND the colour of the pixel at x,y is yellow.

This test destroys a bomb if it hits the ground or falls onto a yellow barrier.

 

1670       bombdead=TRUE:GCOL 0,0:MOVE x,y+2/3*bomb(a,4):VDU 5,234,4

 

Bombs erode barriers. Note the inclusion of '2/3*' which relates to two thirds of the bomb's downward velocity. This is a 'fudge-factor', a minor adjustment of an inconsequential calculation, to make the pattern of erosion appear more realistic.

 

1680     ELSE

1690       IF y<56 AND x>basex-12 AND x<basex+64 playeralive=FALSE:bombdead=TRUE

 

This IF statement tests for a bomb colliding with the player's base, destroying the base and the bomb.

 

1700     ENDIF

1710     IF bombdead THEN

1720       bomb(a,0)=FALSE:bombptr$+=STR$(a)

 

Upon the demise of a bomb the pointer to the row it occupied, in the 'bomb' array, is returned to the stack (bombptr$), ready for reassignment.

 

1730     ELSE

1740       GCOL 0,5:MOVE bomb(a,1),bomb(a,2):VDU 5,234,4

1750     ENDIF

1760   ENDIF

1770 NEXT

1780 ENDPROC

 

If the bomb remains active, then it needs to be redrawn in its updated position.

 

1800 DEF PROCexplode

1810 LOCAL a:REM Destruction of player's base

1820 IF funeral=0 THEN

1830   FOR a=0 TO 9

1840     bomb(a,1)=basex+16:bomb(a,2)=40

1850     bomb(a,3)=RND(128)-64:bomb(a,4)=RND(64)

1860   NEXT

1870 ENDIF

1880 FOR a=0 TO 9

1890   GCOL 0,0:MOVE bomb(a,1),bomb(a,2):VDU 5,233,4

1900   bomb(a,1)+=bomb(a,3)

1910   bomb(a,2)+=bomb(a,4)

1920   GCOL 0,7:MOVE bomb(a,1),bomb(a,2):VDU 5,233,4

1930 NEXT

1940 IF funeral=50 restart=TRUE

1950 funeral+=1

1960 ENDPROC

 

PROCexplode usurps control of the 'bomb' array. Ten blocks of debris, with varying velocities, are entered into this array.

For the next 50 animation frames this routine draws the exploding blocks, moving them away from the remains of the player's base.

When 50 frames have been drawn, 'restart' is set to TRUE to trigger a new life, or the end of the game.

 

 

Pixel Size:

 

It will be apparent that there is a discrepancy between the size of the pixels, as they appear in user-defined characters, and the accuracy to which they can be plotted. In MODE 9, one pixel is equal to 4 graphical 'units' in width and height.

Invaders Arrow black large Arrow black large