Code Sample: Countdown Timer

Below is an example of a countdown timer I’m reasonably in love with. Thanks to the other forum contributors for getting me started with the initial countdown code! Attach it to a parent/level Game Object for best results. Use the getters/setters to access the internal properties and start/stop the timer. Methods are kept out of the way of other scripts to prevent unintended bugs. Best of all, it lets you call a predefined method when the timer is up to handle what to do then (beep, end the level, turn red, etc.).

To invoke in another script, which is what you oughta be doing, do the following. Note that this example assumes that the calling script and countdown timer are components of the same Game Object.

var o_countdownTimer : countdownTimer;
var f_timerdone = timerDone;
o_countdownTimer = GetComponent(countdownTimer);
o_countdownTimer.setStartTime(90.0);
o_countdownTimer.setTimerDoneAction(f_timerdone);
o_countdownTimer.setTimerState(true);

function timerDone() {
	guiText.text = "done!";
}
//countdownTimer: methods to handle a countdown timer
//it is always assumed that there is a guiText item available for the display output

//PRIVATE MEMBERS
private var b_timer_active : boolean; //switch to start/stop timer
private var f_timer_done; //method to be called when timer runs down
private var fl_start_time : float; //start time (in seconds)
private var fl_time_left : float; //time left (in seconds)

//PUBLIC METHODS
function getFlRemainingTime() { //get the time remaining on the clock
	return fl_time_left;
}

function setTimerDoneAction(f_method_fp) { //set the method to be called when the timer is done
	f_timer_done = f_method_fp;
}

function setTimerState(b_active_fp : boolean) { //set the active state of the timer
	b_timer_active = b_active_fp;
}

function setStartTime(fl_time_fp : float) { //set the starting value for the countdown
	fl_start_time = fl_time_fp;
}

function Update() {
	if (b_timer_active) { //check to see if the timer is "on"
		if (!guiText) { //check for an available GUIText component
			Debug.Log("countdownTimer needs a GUIText component!");
			enabled = false;
			return;
		} else {
			doCountdown(); //decrement the time and send value to GUIText for output
		}
	}
}

//PRIVATE METHODS
private function doCountdown() { //
	if (fl_start_time) { //make sure that we had a starting time value before conting down
		fl_time_left = fl_start_time - Time.time; 
		fl_time_left = Mathf.Max(0, fl_time_left); //don't let the time fall below 0.0
		guiText.text = outReadableTime(fl_time_left); //display the time to the GUI
		if (fl_time_left == 0.0) { //if time has run out, deactivate the timer and call the followup method
			b_timer_active = false;
			if (f_timer_done) { //only call the followup method if we had one
				f_timer_done();
			}
		}
	} else {
		Debug.Log("countdownTimer needs a value set for fl_time_left");
	}
}

private function outReadableTime(fl_time_fp : float) { //format the floating point seconds to M:S
	var i_minutes : int;
	var i_seconds : int;
	var i_time : int;
	var s_timetext : String;
	i_time = fl_time_fp;
	i_minutes = i_time / 60;
	i_seconds = i_time % 60;
	s_timetext = i_minutes.ToString() + ":";
	s_timetext = s_timetext + i_seconds.ToString();
	return s_timetext;
}

Thanks for the contribution, phuzzy - saved me some dev time and will certainly help many others.

Just a note, at first I couldn’t get it to work because I had arbetrarily named the larger script “timer.js”. Then, based on error messages, I realized the larger script should be named countdownTimer.js, because it is called by the smaller script. I don’t think the name of the smaller script is important.

The way I set it up in my game is that I created a new empty game object, then created a GUI Text under that, and dropped both scripts onto the GUI Text.

/ Brad

@Phuzzy - The best place to post things you want to share with the community is in the Wiki: http://www.unifycommunity.com/wiki/index.php?title=Scripts

To get numbers like 1:08, 1:07, instead of 1:8, and 1:7, just replace the last two lines with this:

if (i_seconds > 9){
		s_timetext = s_timetext + i_seconds.ToString();
	}
else {
		s_timetext = s_timetext + "0" + i_seconds.ToString();
	}
return s_timetext;

Hey Phuzzy,

thank you for that countdown script!
I made a small adjustment to your script to take the timeSinceLevelLoad, so the Timer always gets reset when a new scene is loaded. (It was driving me crazy, didn’t understand that it takes the time from when the application started: http://forum.unity3d.com/viewtopic.php?p=229240 )
I also added a function for adding seconds to the timer (e.g. PowerUps) and integrated the code by Nathaniel.

Here is my version:

/*
* countdownTimer: methods to handle a countdown timer 
* it is always assumed that there is a guiText item available for the display output 
*
*/

/*
*	Private member variables
*/
private var b_timer_active : boolean; //switch to start/stop timer 
private var f_timer_done; //method to be called when timer runs down 
private var fl_start_time : float; //start time (in seconds) 
private var fl_time_left : float; //time left (in seconds) 
private var fl_time_extra : float; 

/*
*	Public methods
*/
function getFlRemainingTime() { //get the time remaining on the clock 
   return fl_time_left; 
} 

function setTimerDoneAction(f_method_fp) { //set the method to be called when the timer is done 
   f_timer_done = f_method_fp; 
} 

function setTimerState(b_active_fp : boolean) { //set the active state of the timer 
   b_timer_active = b_active_fp; 
} 

function setStartTime(fl_time_fp : float) { //set the starting value for the countdown 
   fl_start_time = fl_time_fp; 
} 


/*
*	Update
*/
function Update() { 
   if (b_timer_active) { //check to see if the timer is "on" 
      if (!guiText) { //check for an available GUIText component 
         Debug.Log("countdownTimer needs a GUIText component!"); 
         enabled = false; 
         return; 
      } else { 
         doCountdown(); //decrement the time and send value to GUIText for output 
      } 
   } 
} 


/*
*	Adding seconds to the countdown, for "powerUps"
*/
function addSeconds( seconds : float ){
	//Debug.Log("Adding " + seconds + " seconds!");
	fl_time_extra += seconds;
}


/*
* Private methods
*/
private function doCountdown() { // 
   if (fl_start_time  b_timer_active) { //make sure that we had a starting time value before conting down 
      fl_time_left = (fl_start_time - Time.timeSinceLevelLoad) + fl_time_extra; 
      fl_time_left = Mathf.Max(0, fl_time_left); //don't let the time fall below 0.0 
      guiText.text = outReadableTime(fl_time_left); //display the time to the GUI 
      if (fl_time_left == 0.0) { //if time has run out, deactivate the timer and call the followup method 
         b_timer_active = false; 
         if (f_timer_done) { //only call the followup method if we had one 
            f_timer_done(); 
         } 
      } 
   } else { 
      Debug.Log("countdownTimer needs a value set for fl_time_left"); 
   } 
} 

private function outReadableTime(fl_time_fp : float) { //format the floating point seconds to M:S 
   var i_minutes : int; 
   var i_seconds : int; 
   var i_time : int; 
   var s_timetext : String; 
   i_time = fl_time_fp; 
   i_minutes = i_time / 60; 
   i_seconds = i_time % 60; 
   s_timetext = i_minutes.ToString() + ":"; 
	if (i_seconds > 9){ 
	      s_timetext = s_timetext + i_seconds.ToString(); 
	   } 
	else { 
	      s_timetext = s_timetext + "0" + i_seconds.ToString(); 
	   } 
	return s_timetext;
}

There’s an easier way to do the following - just use the formatting argument to ToString, such as:

s_timetext = s_timetext + i_seconds.ToString("D2");

It does seem that since this does string concatenation with the plus operator, it will probably run memory allocations. Not much, but it’s something to be aware of. I guess you could either go with mono StringBuilder or you could minimize heap growth by checking to see if the time display has changed before recreating the string - that would reduce the number of allocations from every frame to however many allocs occur in a doCountdown() call per second.

Im creating a game where you control a ball which rolls down a terrain to collect good and bad objects which effect the amount of time you have to complete the terrain. I have used your code so I have a working countdown timer but was wondering if you could help me with a few problems?
The camera is at the side of the ball not above and swings side to side a bit
How do you make the time-bonus part work? I have objects tagged as ‘correct’ and ‘wrong’ but havent got them to effect the timer. Any help??

@melbabez7: Sorry, I stopped watching this thread.

Camera: This is most likely related to the axis rotation of your ball object, make sure it’s not rotated, set all rotations to 0 and try to figure it out then. I also had that problem once.

Time bonus: Call the addSeconds() function on the timer object. You need to have it present in the object you are trying to call the function from. If you don’t know how, check out the basic scripting information in the documentation.

I’m having trouble adding these scripts, what should the file name of the 2 scripts be, what component should they be added to, and what component needs to go on the o_countdownTimer getter?

How would I alter this script to make it so the timer counts down from a specified amount of seconds and once it hits zero seconds a new scene is loaded and if there is any input the timer resets itself and begins the countdown again.

I am trying to make it when a player in the game remains idle after a number of minutes that the game restarts itself.

Phuzzy/3devils,

Any way I could utilise this to create a level start countdown. So when the level loads a 3-2-1 counts down then the controls become active. I am already using an instance of this to keep a rundown timer on my game once the player starts…

I’m guessing that it will need to be in a function Start to call it then a check in Update ?

Regards,

mm

Hi everyone,

I need to call my gameobject(to run when i play) at specified time . So please some one help me to solve with javascripts.

Thanks In Advance
Karthik

I’m looking to reset the timer from some other event, what would be the best way to go about this.

Also there are some errors when using #pragma strict, specifically when assigning a method to the f_timer_done var. Not sure how to get around that…