• Bruce

Let's create an MPAGD game: Part 29: Adding a timer/countdown to your game

Suppose in your game you want to give the player a set amount of time to complete each screen. And then, perhaps, give them a bonus dependent on the amount of time left when they successfully complete the levels objectives.


How would we go about that?


First, MPAGDD runs at 25 frames per second, so it should be pretty simple to create a timing mechanism that can count second.


Second, we'll need some variables to store (and display) the current amount of minutes/seconds remaining.


Third, we might want to change the amount of time allowed on a per screen basis, or maybe use difficulty levels to alter the amount of time allowed.


METHOD 1 - Simple: Same amount of time per screen

We'll start off with a simple version, where for each screen there is a fixed amount of seconds and minutes allowed to complete the screen, if the timer reaches 0 the player dies.


Now, MPAGD runs at 25 frames per second. So if we have a variable that increments once every frame, when it reaches 25 we'll have timed a second.


We'll use variable G as our general time, counting the 1/25th of seconds.


We'll also need variables that store the number of minutes and seconds allowed per screen:


M = Minutes

S = Seconds.


We'll initialise the values for these three variables in our RESTART SCREEN event, that way, they will reset each time we start a screen, including after a death. In your restart screen event you will add:



LET G = 0         ; reset the 1/25s timer
LET M = 1         ; countdown minutes allowed
LET S = 0         ; countdown seconds allowed

Next, we'll add some code that will perform and display the countdown, to ensure this runs consistently throughout the game we will put this into the MAINLOOP 1 event so that it will run at the start of each frame:



; COUNTDOWN TIMER
;================

ADD 1 TO G               ; increment the general timer
IF G = 25                ; when it reaches 25
   LET G = 0             ; reset it
   SUBTRACT 1 FROM S     ; decrement seconds remaining
ENDIF

IF S = 0                 ; if 0 seconds
   IF M = 0              ; and 0 minutes left
      KILL               ; kill the player
      EXIT               ; exit processing this event
   ENDIF
   SUBTRACT 1 FROM M     ; decrement the minutes
   LET S = 59            ; reset the seconds
ENDIF

COLOUR 71                ; white text on black (zx spectrum)                 
AT 22 26
DISPLAY DOUBLEDIGITS M   ; display minutes remaining
CHR 58                   ; ':'
DISPLAY DOUBLEDIGITS S   ; display seconds remaining

So, we increment G, when it hits 25 we reset it to 0 and decrement the number of seconds (S) when S reaches 0 we reset it to 59 and decrement the number of minutes, unless there are no minutes left in which case we have run out of time and we kill the player, here's what it should look like...





METHOD 2 - Advanced: Different amount of time per screen

If we want to alter the amount of time available we just need to change the variable initialisation code in our RESTART SCREEN event to use a DATA table and READ the values for Minutes (M) and Seconds (S)


We can use this for the variable initialisation in the RESTART SCREEN

LET G = 0           ; reset the 1/25s timer
RESTORE             ; restore the data table so we read from the start
READ M              ; read the 1st data and put it in M
READ S              ; read 2nd value put it in S
IF SCREEN >= 1      ; if it is screen 1 or above
   REPEAT SCREEN    ; then repeat SCREEN-many times
   READ M           ; read the next value for M
   READ S           ; and the next value for S
   ENDREPEAT        ; so we've found the right M & S values for the Screen
ENDIF

Then we will add this as our DATA table, the values alternate from minutes to seconds, so the SCREEN 0 allowable time is 0 minute 30 seconds (the first 2 values), for SCREEN 1 its 1 minute 0 Seconds (values 3 & 4), for Screen 2 it's 1 minute 15 seconds (values 5 & 6) and so on.


DATA 0 30 1 0 1 15 2 0 1 45 1 30 1 0 1 30 

Adding a Bonus for completing the screen


Everything we've done so far is fine for killing the player if they run out of time, but what if they complete the screens objectives, we could add a bonus based on the amount of time remaining. Dependent on what triggers the completion of the screen (in Stinky Dog it's collecting all the bones) you will need to add your bonus routine in the correct event. It might be something like this:



   IF M > 0             ; if there are minutes left
      REPEAT M          ; repeat for each minute remaining
	 REPEAT 60      ; repeat 60 times (60 sec)
	    BONUS 10    ; increase bonus by 10
	 ENDREPEAT
      ENDREPEAT
   ENDIF
   IF S > 0             ; if there are seconds left
      REPEAT S          ; repeat for each second
	 BONUS 10       ; increase the bonus by 10
      ENDREPEAT
   ENDIF
   ADDBONUS             ; add the bonus to the score
   ZEROBONUS            ; reset bonus to zero


Applying this to our Stinky Dog game


In our Stinky Dog game though, there's a couple of changes I want to make.


First we already have a DATA table in RESTART SCREEN 0, it holds the number of bones that need to be collected per screen. No problem, MPAGD doesn't care what the data it holds in the DATA table - so we just need to include the bones values and READ three times per cycle to get the correct number of bones, minutes and seconds.



LET G = 0           ; reset the 1/25s timer
RESTORE             ; restore the data table so we read from the start
READ M              ; read the 1st data and put it in M
READ S              ; read 2nd value put it in S
READ B              ; read third value and put it in B for Bones
IF SCREEN >= 1      ; if it is screen 1 or above
   REPEAT SCREEN    ; then repeat SCREEN-many times
   READ M           ; read the next value for M
   READ S           ; and the next value for S
   READ B           ; and the next values for B
   ENDREPEAT        ; we've found the right M, S & B values for the Screen
ENDIF



And the DATA table at the bottom of RESTART SCREEN:


DATA 0 30 6 1 0 7 1 15 3 2 0 4 1 45 6 1 
DATA 30 4 1 0 8 1 30 6 



Next, as we've already created a nice reusable death routine which we call by setting Stinky Dog's SETTINGA value to 99, I'm going to move the Countdown Timer code from MAINLOOP 1 to the player event, remove the KILL command and change it to LET SETTINGA = 99


NOTE: Place the code AFTER your IF SETTINGA = 99 ....ENDIF routine



; COUNTDOWN TIMER
;================

ADD 1 TO G               ; increment the general timer
IF G = 25                ; when it reaches 25
   LET G = 0             ; reset it
   SUBTRACT 1 FROM S     ; decrement seconds remaining
ENDIF

IF S = 0                 ; if 0 seconds
   IF M = 0              ; and 0 minutes left
      LET SETTINGA = 99  ; kill the player
      EXIT               ; exit processing this event
   ENDIF
   SUBTRACT 1 FROM M     ; decrement the minutes
   LET S = 59            ; reset the seconds
ENDIF

COLOUR 71                ; white text on black (zx spectrum)                 
AT 22 26
DISPLAY DOUBLEDIGITS M   ; display minutes remaining
CHR 58                   ; ':'
DISPLAY DOUBLEDIGITS S   ; display seconds remaining





Here it is in action when we run out of time



To add a new time bonus on completing the screen we'll need to update our COLLECT BLOCK event:


EVENT COLLECTBLOCK

SCORE 100                  	; score 100 points when we collect a Bone
AT 0 6 
COLOUR 71
SHOWSCORE			; display the score

SUBTRACT 1 FROM B	; decrement the number of bones left on screen
IF B = 0                ; have all Bones been collected?
   CLS                  ; clear the screen
   AT 4 6
   MESSAGE 1            ; "well done"
   CHR 32
   MESSAGE 0            ; "stinky dog"
   CHR 33
   DELAY 25             ; wait another second
   COLOUR 65            ; bright blue on balck
   AT 7 7
   MESSAGE  2           ; "score"
   CHR 32               ; <space>
   DELAY 25             ; wait another second
   SHOWSCORE
   DELAY 25             ; wait another second
   AT 9 2
   COLOUR 70            ;  bright yellow on black
   MESSAGE 3            ; "fart"
   CHR 32               ; <space>
   MESSAGE 4            ; "bonus"
   CHR 32               ; <space>
   DELAY 25             ; wait another second
   SHOWBONUS            ; display the bonus
   ADDBONUS             ; add the bonus to the score
   ZEROBONUS            ; reset the bonus to 0 now we've added it
   DELAY 25             ; wait another second
   COLOUR 67            ; bright magenta on black
   AT 11 2
   MESSAGE 7            ; "time"
   CHR 32               ; <space>
   MESSAGE 4            ; "bonus"
   CHR 32               ; <space>
   DELAY 25             ; wait another second
   IF M > 0             ; if there are minutes left
      REPEAT M          ; repeat for each minute remaining
	 REPEAT 60      ; repeat 60 times (60 sec)
	    BONUS 10       ; increase bonus by 10
	 ENDREPEAT
      ENDREPEAT
   ENDIF
   IF S > 0             ; if there are seconds left
      REPEAT S          ; repeat for each second
	 BONUS 10       ; increase the bonus by 10
      ENDREPEAT
   ENDIF
   SHOWBONUS
   ADDBONUS             ; add the bonus to the score
   ZEROBONUS            ; reset bonus to zero  
   AT 13 5                
   COLOUR 71
   MESSAGE 8            ; "total"
   CHR 32
   CHR 61
   CHR 32 
   SHOWSCORE            ; display the score
   DELAY 25             ; wait 1 second

   AT 17 8              ; at line 15 column 8
   COLOUR 215
   MESSAGE 5            ; "press key to start"
   WAITKEY              ; wait for a key press
   NEXTLEVEL            ; if so move to the next screen
ENDIF

Note that I've added two new messages to the TEXT MESSAGES:


DEFINEMESSAGES
"STINKY DOG"          ;0
"WELL DONE"           ;1
"SCORE"               ;2
"FART"                ;3
"BONUS"               ;4
"PRESS KEY TO START"  ;5
"LIVES"               ;6
"TIME"                ;7 
"TOTAL"               ;8



Here it is all working nicely!










67 views0 comments