Programming Techniques: Bat And Ball Demo

By Dominic Ford

Originally published in EUG #39

This simple game was written to illustrate the user of the User-Defined Characters module to a BASIC programmer wanting to achieve high-speed graphics. The program was purposely written entirely in BASIC to illustrate how you don't need any knowledge of machine code to use the system.

These instructions consist of two parts: firstly instructions on how to play the game, and then a detailed line-by-line breakdown of how it actually works.

Playing instructions

When you start the game, you are confronted by a ball bouncing around the screen and a bat at the bottom of the screen which you can move left and right using the Z and X keys. The idea, as with all "BREAKOUT-style" games, is to move the bat so that the ball bounces off it and does not go off the bottom of the screen. When the ball strikes one of the blocks at the top of the screen, it disappears.

If you fail to hit the ball with the bat, the ball will freeze. Press SPACE to restart it - it will restart again from its initial position.

Program Notes

This program is intended as a demonstration of what the sprites module can do, and I would encourage you to print it out and study the BASIC more closely. There follows a list of the variables used, and a line-by-line breakdown of what the program does.

Variable list:

(xball, yball) The position of the ball on the screen, measured in pixels
xbat The x position of the bat at the bottom of the screen, measured in characters.
(xnew, ynew) Used as a temporary storage area while new co-ordinates are being worked out. This means that the removal of the old image can be left as late as possible to reduce flicker to a minimum.
left Is the ball moving left? (TRUE = left, FALSE = right)
up Is the ball moving up? (TRUE = up, FALSE = down)

Unfortunately, I only tried out the program on an Electron at the last minute (having written it on a Beeb) and had to make a few alterations. Therefore, the program comments that follow should be used in conjunction with the program listed with the comments, not with BATBALL itself. Also, I only found out how terribly slow it runs on an Elk at the last minute, but didn't have time to sort that one out. You should get the idea, though.

[Standard first two lines of a UDCMod based program]

    10 MODE2:HIMEM=&2C00:PROCasschar
    20 REM Put your program code here!
[Set EOR paint style so that ball can easily be erased]
    30 PROCsetpaint(3)
[Set up array which stores which blocks have been hit by ball]
    40 DIMblock(19,9)
[Draw blocks at top of the screen]
    50 ?xoff=0:?yoff=0:FORx=0TO19:FORy=0TO9:?char=1+RND(2):?xc=x:?yc=y:C
   ALLdisplay:NEXT:NEXT
[Set initial position of ball]
    60 xball=37:yball=100:up=FALSE:left=FALSE
[and of the bat...]
    70 xbat=9
[Draw bat in initial position]
    80 ?char=4:?xc=9:?yc=30:?xoff=0:?yoff=0:CALLdisplay:?xc=10:?char=5:C
   ALLdisplay
[and ball as well...]
    90 ?char=0:?xc=xball DIV4:?yc=yball DIV8:?xoff=xball AND3:?yoff=yball
   AND7:CALLdisplay
[Finished setting up, so start main loop]
   100 REPEAT
[Move ball and put new position in (xnew,ynew)]
   110 IF left THEN xnew=xball-2 ELSE xnew=xball+2
   120 IF up THEN ynew=yball-4 ELSE ynew=yball+4
[Bouncing off top of screen?]
   130 IF ynew<4 THEN up=FALSE
[If bounce off bottom of screen, beep, wait for space, and put ball back in initial position]
   140 IF ynew=248 THEN VDU7:REPEAT UNTIL INKEY(-99):xnew=37:ynew=100
[Bouncing off left/right of screen?]
   150 IF xnew=1 THEN left=FALSE
   160 IF xnew=75 THEN left=TRUE
[Erase old picture of ball]
   170 ?char=0:?xc=xball DIV4:?yc=yball DIV8:?xoff=xball AND3:?yoff=ybal
   lAND7:CALLdisplay
[and replace with new picture of ball]
   180 xball=xnew:yball=ynew
   190 ?char=0:?xc=xball DIV4:?yc=yball DIV8:?xoff=xball AND3:?yoff=ybal
   lAND7:CALLdisplay
[Bouncing off bat?]
   200 IF yball=232 AND (xball>(xbat-2)*4) AND (xball<(xbat+2)*4) THEN u
   p=TRUE
[If ball is not in area containing blocks, don't check if it's hit one!]
   210 IF yball>80 THEN GOTO 330
[Move ball's position to integer variables for speed. Also set standard paint style as this is how blocks are removed]
   220 xb%=xball DIV4:yb%=yball DIV8:PROCsetpaint(0)
[Hit a block above? If so, remove it. This involves painting a black square on the screen, and setting in the block array that it has gone! Also make ball bounce off downwards...]
   230 IF up AND yb%<>0 THEN IF block(xb%,yb%-1)=0THENup=FALSE:block(xb%
   ,yb%-1)=1:?char=6:?xc=xb%:?yc=yb%-1:?xoff=0:?yoff=0:CALLdisplay
[Hit block diagonally up and left?]
   240 IF up AND left AND yb%<>0 AND xb%<>0 THEN IF block(xb%-1,yb%-1)=0
   THENup=FALSE:left=FALSE:block(xb%-1,yb%-1)=1:?char=6:?xc=xb%-1:?yc=yb
   %-1:?xoff=0:?yoff=0:CALLdisplay
[Hit block diagonally up and right?]
   250 IF up AND (NOT left) AND yb%<>0 AND xb%<19 THEN IF block(xb%+1,xb
   %-1)=0THENup=FALSE:left=TRUE:block(xb%+1,yb%-1)=1:?char=6:?xc=xb%+1:?
   yc=yb%-1:?xoff=0:?yoff=0:CALLdisplay
[Hit block down below ball?]
   260 IF NOT up AND yb%<9 THEN IF block(xb%,yb%+1)=0THENup=TRUE:block(x
   b%,yb%+1)=1:?char=6:?xc=xb%:?yc=yb%+1:?xoff=0:?yoff=0:CALLdisplay
[Hit block diagonally below and left?]
   270 IF (NOT up) AND left AND xb%<>0 AND yb%<9 THEN IF block(xb%-1,yb%
   +1)=0 THENup=TRUE:left=FALSE:block(xb%-1,yb%+1)=1:?char=6:?xc=xb%-1:?
   yc=yb%+1:?xoff=0:?yoff=0:CALLdisplay
[Hit block diagonally below and right?]
   280 IF (NOT up) AND (NOT left) AND xb%<19 AND yb%<9 THEN IF block(xb%
   +1,yb%+1)=0THENup=TRUE:left=TRUE:block(xb%+1,yb%+1)=1:?char=6:?xc=xb%
   +1:?yc=yb%+1:?xoff=0:?yoff=0:CALLdisplay
[If we are in row 10, we don't have to check blocks left or right, so we can skip these checks]
   290 IF yb%>9 THEN GOTO 320
[Hit block to left?]
   300 IF left AND xb%<>0 THEN IF block(xb%-1,yb%)=0THENleft=FALSE:block
   (xb%-1,yb%)=1:?char=6:?xc=xb%-1:?yc=yb%:?xoff=0:?yoff=0:CALLdisplay
[Hit block to right?]
   310 IF NOT left AND xb%<19 THEN IF block(xb%+1,yb%)=0THENleft=TRUE:bl
   ock(xb%+1,yb%)=1:?char=6:?xc=xb%+1:?yc=yb%:?xoff=0:?yoff=0:CALLdisplay
[Now that we've got block-hitting out of the way, we can go back to the EOR paint style, as that's how the bat and ball are drawn]
   320 PROCsetpaint(3)
[Is bat moving left?]
   330 xnew=-1:IF INKEY(-98) AND xbat<>0 THEN xnew=xbat-0.5
[Is bat moving right?]
   340 IF INKEY(-67) AND xbat<>18 THEN xnew=xbat+0.5
[Has bat moved at all? If xnew is still -1, the value it was set to in 330, clearly not!]
   350 IF xnew=-1 THEN UNTIL FALSE
[Remove old bat, which is two sprites wide]
   360 ?char=4:?xc=INT(xbat):?yc=30:?xoff=(xbat*4)AND2:?yoff=0:CALLdispa
   y:?xc=?xc+1:?char=5:CALLdisplay
[Draw new bat]
   370 xbat=xnew
   380 ?char=4:?xc=INT(xbat):?xoff=(xbat*4)AND2:CALLdisplay:?xc=?xc+1:?c
   har=5:CALLdisplay
[That's it - we're done! Go round the whole loop again...]
   390 UNTIL FALSE
   400 END

Dominic Ford, EUG #39