Breakout

TUTORIAL · BREAKOUT · STAGE 7 OF 8BETA

Stage 7 · Lives, game over and restart

Three lives, a GAME OVER banner, and SPACE to start again from level 1.

GAME OVER and PRESS SPACE over the brick field with LIVES 0 on the HUD
The end of a game, photographed from the finished game (stage 7 looks the same).

Type these 4 lines into the previous stage. Lines 50 and 340 replace lines you already have: type them again in full. Or load the whole stage from the disc with CHAIN "STAGE7".

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.

50 p%=152                                        :REM bat X, left edge: always a multiple of 4
    :b%=160:y%=192                               :REM ball top-left, sitting on the bat
    :sv%=1                                       :REM 1 = ball waits on the bat for SPACE
    :d%=4                                        :REM 3 or more = full redraw of both pages next frame
    :u%=b%:v%=y%:w%=p%                           :REM ball and bat last frame
    :aa%=b%:bb%=y%:cc%=p%                        :REM and the frame before: what the hidden page shows
    :G%=0                                        :REM no GAME OVER banner. Resident integers survive
    REM RUN and CHAIN, so clear them on every start
127 IF lv%=0 AND sp% G%=0                        :REM game over and SPACE: restart, banner off
    :l%=0:sc%=0:lv%=3                            :REM level 0, because PROCnextlevel adds one
    :PROCnextlevel                               :REM build level 1 and put the ball on the bat
    :e%=4:f%=-4                                  :REM starting speed (PROCnextlevel just set 5)
175 IF G% PROCegtext("GAME OVER",120,140)        :REM game over: the banner, once per
    :PROCegtext("PRESS SPACE",112,156)           :REM page while G% counts 2, 1
    :G%=G%-1
340 IF ny%>240 sv%=1:f%=-4                       :REM off the bottom: missed. Serve again...
    :nx%=p%+8:ny%=192                            :REM ...from the bat
    :lv%=lv%-1:hd%=2                             :REM lose a life, HUD on both pages
    :IF lv%=0 G%=2:sv%=2                         :REM last life: GAME OVER banner, and sv%=2
    REM hides the ball until SPACE restarts (line 127)

Line 340 now takes a life for every missed ball. Losing the last one sets sv%=2, which line 181 reads as "do not draw the ball", and G%=2, which line 175 uses to write GAME OVER and PRESS SPACE on both pages. Line 127 restarts on SPACE: score, lives and level go back to the start, and PROCnextlevel (with l%=0) builds level 1 and puts the ball on the bat.

G% is one of BBC BASIC's resident integers (A% to Z%). They live at fixed addresses, are shorter to tokenise, and survive RUN and CHAIN, which is useful for passing values between programs but means a leftover value from the last run is still there. Line 50 sets G%=0 for that reason.

The whole of stage 7, ready to type in: the EGFX helpers merged and the notes stripped (92 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%:G%=0
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
127 IF lv%=0 AND sp% G%=0:l%=0:sc%=0:lv%=3:PROCnextlevel:e%=4:f%=-4
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
175 IF G% PROCegtext("GAME OVER",120,140):PROCegtext("PRESS SPACE",112,156):G%=G%-1
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:lv%=lv%-1:hd%=2:IF lv%=0 G%=2:sv%=2
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):ENDPROC

Try it: give an extra life every 1000 points (watch out: sc% goes up in tens, so test with MOD), or add a short pause before GAME OVER.

← Stage 6: Score and HUD Stage 8: Sound →