TUTORIAL · BREAKOUT · STAGE 6 OF 8BETA
Stage 6 · Score and HUD
A score, level and lives line across the top, redrawn only when something changes and kept out of the busiest frames.

Type these 6 lines into the previous stage. Lines 30, 60, 394 and 410 replace lines you already have: type them again in full. Or load the whole stage from the disc with CHAIN "STAGE6".
Text after :REM and indented continuation lines are Beeb-dev notes and layout: the build strips them, so they cost the BBC nothing. Typing into a real BBC, leave the notes out and join each continuation line onto the line above.
30 DIM a%(5,7) :REM brick strengths: 6 rows by 8, 0 = gone
:l%=1 :REM level (PROCnextlevel adds one as it starts a level)
:e%=4:f%=-4 :REM ball velocity in pixels a frame: right and up
:sc%=0:lv%=3:hd%=0 :REM score, lives, no HUD redraw owed yet
:PROCresetlevel :REM fill the grid for level 1
60 REPEAT :REM one pass of the loop is one frame
:IF d%>=3 PROCegbegin :REM new level: the rest of line 60 runs only now.
REM BEGIN clears the hidden page...
:PROCdrawbricks:PROCdrawhud :REM ...draws the wall and the HUD...
:PROCbatdraw(p%):PROCegpresent :REM ...and the bat, then shows it at vsync
:PROCegbegin:PROCdrawbricks :REM the same again, because the Master has two
:PROCdrawhud:PROCbatdraw(p%) :REM screen pages and both must hold the field
:PROCegpresent :REM before dirty frames can start
:d%=0 :REM from here on, repaint only what changes
:aa%=p%:u%=p%:bb%=192:v%=192 :REM both pages are fresh, so restart the ball's
REM erase history (any old position is already clean)
170 IF hd% hd%=hd%-1 :REM a HUD redraw is owed: count down...
:IF hd%<2 PROCdrawhud :REM ...and draw on the last two counts, once per
REM page. A broken brick sets 4, so the HUD waits two frames and
REM does not land on the brick's erase frames
394 a%(rr%,ct%)=0:n%=n%-1 :REM broken: one fewer brick
:sc%=sc%+10 :REM ten points
:hd%=4 :REM HUD in two frames' time (line 170)
:IF n%=0 PROCnextlevel :REM that was the last one: next level
410 DEF PROCnextlevel
:l%=l%+1 :REM next level
:e%=4+l%:f%=-e% :REM one pixel a frame faster each time
:PROCresetlevel :REM a fresh wall
:sv%=1 :REM ball back on the bat
:d%=4 :REM redraw everything on both pages
:hd%=2 :REM and the HUD on both pages
:ENDPROC
440 DEF PROCdrawhud :REM one line of text, every number padded to a
REM fixed width, so the new HUD exactly covers the old one
:PROCegtext("SCORE "+RIGHT$("00000"+STR$(sc%),5) :REM SCORE 00230
+" LEVEL "+RIGHT$("00"+STR$(l%),2) :REM LEVEL 01
+" LIVES "+STR$(lv%) :REM LIVES 3
,8,8):ENDPROC :REM at (8,8). EGFX text is opaque: no erase needed
One line of text
440 DEF PROCdrawhud :REM one line of text, every number padded to a
REM fixed width, so the new HUD exactly covers the old one
:PROCegtext("SCORE "+RIGHT$("00000"+STR$(sc%),5) :REM SCORE 00230
+" LEVEL "+RIGHT$("00"+STR$(l%),2) :REM LEVEL 01
+" LIVES "+STR$(lv%) :REM LIVES 3
,8,8):ENDPROC :REM at (8,8). EGFX text is opaque: no erase needed
EGFX text is opaque and every number is zero-padded to a fixed width, so the new HUD completely covers the old one and needs no erase first. It is still the most expensive single thing the game draws, so it is not drawn every frame.
Redraw counters
170 IF hd% hd%=hd%-1 :REM a HUD redraw is owed: count down...
:IF hd%<2 PROCdrawhud :REM ...and draw on the last two counts, once per
REM page. A broken brick sets 4, so the HUD waits two frames and
REM does not land on the brick's erase frames
394 a%(rr%,ct%)=0:n%=n%-1 :REM broken: one fewer brick
:sc%=sc%+10 :REM ten points
:hd%=4 :REM HUD in two frames' time (line 170)
:IF n%=0 PROCnextlevel :REM that was the last one: next level
hd% counts the frames that still owe a HUD redraw. Like a broken brick, a change has to be drawn once on each page. A lost life or a new level sets hd%=2 (both of the next two frames). A broken brick sets hd%=4, and line 170 only draws while the counter is below 2, so the redraw happens on the third and fourth frames after the hit, after the two frames that rub out the brick. Doing it all at once made the hit frame the slowest frame in the game.
Lives are on the HUD but nothing takes them away yet: the ball still just comes back to the bat.
The whole of stage 6, ready to type in: the EGFX helpers merged and the notes stripped (90 BASIC lines)
5 MODE 1:HIMEM=&2400
20 PROCeginit:PROCegcompanion(7,&81,255)
30 DIM a%(5,7):l%=1:e%=4:f%=-4:sc%=0:lv%=3:hd%=0:PROCresetlevel
40 PROCstartscreen
50 p%=152:b%=160:y%=192:sv%=1:d%=4:u%=b%:v%=y%:w%=p%:aa%=b%:bb%=y%:cc%=p%
60 REPEAT:IF d%>=3 PROCegbegin:PROCdrawbricks:PROCdrawhud:PROCbatdraw(p%):PROCegpresent:PROCegbegin:PROCdrawbricks:PROCdrawhud:PROCbatdraw(p%):PROCegpresent:d%=0:aa%=p%:u%=p%:bb%=192:v%=192
65 PROCegdirtybegin
75 z%=INKEY(-98):x%=INKEY(-67):sp%=INKEY(-99)
80 IF z% p%=p%-12
90 IF x% p%=p%+12
100 IF p%<8 p%=8
110 IF p%>288 p%=288
120 IF sv%=1 b%=p%+8:y%=192:IF sp% sv%=0
130 IF sv%=0 PROCmoveball
150 IF aa%<>b% OR bb%<>y% PROCegcompact(aa%,bb%,1,0,7,&87)
155 IF cc%<>p% PROCbatclear(cc%)
160 IF d%>0 AND d%<3 PROCbe
161 IF d%>0 AND d%<3 d%=d%-1
170 IF hd% hd%=hd%-1:IF hd%<2 PROCdrawhud
180 IF cc%<>p% OR (bb%<=205 AND bb%+7>=202 AND aa%<=p%+15 AND aa%+7>=p%) PROCbatdraw(p%)
181 IF sv%<>2 PROCegcompact(b%,y%,0,0,7,&87)
185 aa%=u%:bb%=v%:cc%=w%:u%=b%:v%=y%:w%=p%
190 PROCegpresent
200 UNTIL INKEY(-17)
210 MODE 7:END
220 DEF PROCstartscreen
230 PROCegbegin:FOR y%=24 TO 88 STEP 8:PROCegline(40,y%,280,y%,(y% DIV 8) MOD 4):NEXT:PROCegtext("BRICKFALL",120,48):PROCegline(64,80,256,80,3)
240 PROCegtext("PRESS SPACE",112,176):PROCegpresent
250 REPEAT:UNTIL INKEY(0)=32:*FX 15
260 ENDPROC
300 DEF PROCmoveball
310 nx%=b%+e%:ny%=y%+f%
320 IF nx%<=8 nx%=8:e%=-e%
325 IF nx%>=288 nx%=288:e%=-e%
330 IF ny%<24 ny%=24:f%=-f%
340 IF ny%>240 sv%=1:f%=-4:nx%=p%+8:ny%=192
350 IF ny%<=205 AND ny%+7>=202 AND f%>0 AND nx%+3>=p% AND nx%+3<p%+16 ny%=194:f%=-f%:e%=e%+SGN(nx%+3-p%-8)
355 IF ny%>107 OR ny%+7<40 OR nx%+7<64 OR nx%>247 GOTO 380
360 r0%=(ny%-40)DIV12:IF r0%<0 r0%=0
362 r1%=(ny%+7-40)DIV12:IF r1%>5 r1%=5
364 c0%=(nx%-64)DIV24:IF c0%<0 c0%=0
366 c1%=(nx%+7-64)DIV24:IF c1%>7 c1%=7
368 h%=0:FOR rr%=r0% TO r1%:FOR ct%=c0% TO c1%
370 IF h%=0 AND a%(rr%,ct%)>0 PROCbrickhit
372 NEXT:NEXT
380 b%=nx%:y%=ny%:ENDPROC
382 DEF PROCbrickhit
384 IF nx%>79+ct%*24 OR nx%+7<64+ct%*24 OR ny%>47+rr%*12 OR ny%+7<40+rr%*12 ENDPROC
385 IF d%=1 PROCbe
386 h%=1:hr%=rr%:hc%=ct%:d%=2
388 IF y%+7<40+rr%*12 OR y%>47+rr%*12 f%=-f% ELSE e%=-e%
390 nx%=b%+e%:ny%=y%+f%
392 IF a%(rr%,ct%)>1 a%(rr%,ct%)=a%(rr%,ct%)-1:ENDPROC
394 a%(rr%,ct%)=0:n%=n%-1:sc%=sc%+10:hd%=4:IF n%=0 PROCnextlevel
396 ENDPROC
400 DEF PROCresetlevel:n%=0:FOR r%=0 TO 5:FOR c%=0 TO 7
402 s%=1:IF l%>1 s%=1+((r%+c%+l%)MOD 3)
404 a%(r%,c%)=s%:n%=n%+1:NEXT:NEXT:ENDPROC
410 DEF PROCnextlevel:l%=l%+1:e%=4+l%:f%=-e%:PROCresetlevel:sv%=1:d%=4:hd%=2:ENDPROC
420 DEF PROCdrawbricks:FOR r%=0 TO 5:egb%?8=8:FOR c%=0 TO 7:egb%?(16+c%*5)=2+r%:egb%?(17+c%*5)=(64+c%*24) AND 255:egb%?(18+c%*5)=0:egb%?(19+c%*5)=40+r%*12:egb%?(20+c%*5)=0:NEXT:PROCegcall(34):NEXT:ENDPROC
440 DEF PROCdrawhud:PROCegtext("SCORE "+RIGHT$("00000"+STR$(sc%),5)+" LEVEL "+RIGHT$("00"+STR$(l%),2)+" LIVES "+STR$(lv%),8,8):ENDPROC
500 DEF PROCbatclear(x%):bt%=&6E82+2*x%:FOR q%=0 TO 3:!bt%=0:bt%=bt%+8:NEXT:ENDPROC
510 DEF PROCbatdraw(x%):bt%=&6E82+2*x%:FOR q%=0 TO 3:!bt%=&FF0F0FFF:bt%=bt%+8:NEXT:ENDPROC
530 DEF PROCbe:PROCegcompact(64+hc%*24,40+hr%*12,9+SGN(a%(hr%,hc%))*(hr%-7),0,7,&81):ENDPROC
1000 DEF PROCeginit
1010 IF HIMEM>&2400 OR TOP>&2200 PRINT "EGFX MEM":END
1020 DIM egb% 63:LOCAL egi%
1025 FOR egi%=0 TO 63:egb%?egi%=0:NEXT
1040 egb%?0=64:egb%?1=8:egb%?2=69:egb%?3=71:egb%?4=1
1045 PROCegcall(0):ENDPROC
1050 DEF PROCegcall(egf%)
1070 egb%?5=egf%:egb%?7=0
1080 A%=&C0:X%=egb% MOD 256:Y%=egb% DIV 256:CALL &FFF1
1090 IF egb%?7<>&A5 PRINT "NO EGFX ROM":END
1095 IF egf%>=11 AND egf%<>22 AND egf%<>23 AND egb%?6<>0 PRINT "EG ERROR":END
1100 ENDPROC
1110 DEF PROCegxy(egx%,egy%)
1120 egb%?8=egx%:egb%?9=egx% DIV 256
1130 egb%?10=egy%:egb%?11=egy% DIV 256:ENDPROC
1140 DEF PROCegbegin:PROCegcall(1):ENDPROC
1144 DEF PROCegdirtybegin:egb%?8=255:PROCegcall(38):ENDPROC
1150 DEF PROCegpresent:PROCegcall(6):ENDPROC
1180 DEF PROCegtext(egs$,egx%,egy%)
1190 PROCegxy(egx%,egy%):$(egb%+22)=egs$+CHR$0:PROCegcall(7):ENDPROC
1260 DEF PROCegline(egx%,egy%,egex%,egey%,egc%)
1270 PROCegxy(egx%,egy%):egb%?13=egc%:egb%?16=egex% AND 255:egb%?17=(egex% AND &FFFF) DIV 256
1280 egb%?20=egey% AND 255:egb%?21=(egey% AND &FFFF) DIV 256:PROCegcall(10):ENDPROC
1820 DEF PROCegcompanion(b%,p%,h%):egb%?8=b%:egb%?9=p%:egb%?10=h%:PROCegcall(33):ENDPROC
2110 DEF PROCegcompact(x%,y%,i%,f%,b%,p%)
2120 PROCegxy(x%,y%):egb%?12=i%:egb%?14=f%:egb%?16=b%:egb%?17=p%:PROCegcall(37):ENDPROCTry it: score 10, 20 and 30 by row band. Or show a high score (it can live in a resident integer such as H%, which survives RUN).
← Stage 5: Strong bricks and levels Stage 7: Lives, game over and restart →