Bruce

Nov 7, 20217 min

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!

    4410
    3