Unity: TimerClass

Ok, for seasoned (or maybe even not-so-seasoned) Unity developers, this is probably nothing. But I have been childishly happy about this TimerClass I’m trying to implement. It’s simplicity is what makes it exciting.

The TimerClass that I’m coding is a self-contained timer whose only requirement is that it is updated per Time.deltaTime; thus it needs to be called at the top of every Update(). This works for me because it’s neat to see all the timers up in one area instead of spread out through the code.

Before I get into the specific things that I like, this is how  the code looks like (written in Unityscript/Javascript):

#pragma strict

// This TimerClass keeps track of a timer
class TimerClass
{
	var timer_name:String;
	var end_time:float = 0; // the end time before the timer sends a signal to say time is up
	var counter: float = 0; // the counter for time
	var switchname:String; // whether the timer should keep on adding delta time or not
	var component:Component;
	var expired:boolean = false; // this notes whether the Timer had been previously started and now has expired; needs StartTimer do make a clean start
	// this.GetType().GetField(attrname).SetValue(this,parseInt(str));
	function TimerClass()
	{
		
	}
	function TimerClass(tn:String, sn:String, et:float, c:Component)
	{
		timer_name = tn;
		switchname = sn;
		end_time = et;
		component = c;
	}
	function UpdateTime(val:float)
	{
		var timerswitch = component.GetType().GetField(switchname).GetValue(component);
		if(timerswitch == true) // if the switch is TRUE
		{
			if(TimeUp() == false) // if the time is not up, then keep on adding time to the counter
				counter += val;
			else
			{
				component.SendMessage(timer_name+"_TimeUp",SendMessageOptions.DontRequireReceiver);
				EndTimer(); // end timer itself
			}
			
		}
	}
	function IsRunning()
	{
		var timerswitch = component.GetType().GetField(switchname).GetValue(component);
		return(timerswitch); // if the swtich is on, this means the timer is running
	}
	function StartTimer()
	{
		// this makes the switchname turn on
		component.GetType().GetField(switchname).SetValue(component,true);
		ResetTimer();
	}
	function StopTimer()
	{
		component.GetType().GetField(switchname).SetValue(component,false);
	}
	function EndTimer()
	{
		component.GetType().GetField(switchname).SetValue(component,false);
		expired = true;
	}
	function ResetTimer() // returns true if time is up
	{
		counter = 0;
		expired = false;
	}
	function TimeUp() // returns true if time is up
	{
		return(counter >= end_time);
	}

}

The two things that I like about this TimerClass is its feature to query a conditional boolean variable directly from the source Component that instantiated it, and the SendMessage mechanism based on the timer’s name, which is mandatory.

The class is instantiated in this way:

Timer = TimerClass("WaitTimer","is_waiting",5,this);

The first argument is the name of the timer, and this is concatenated with “_TimeUp” in order to form the SendMessage function. In the same script, a function is thus defined:


function WaitTimer_TimeUp()
{
...
}

The second argument is the ‘switch’ variable, which is a variable that is local to script. Note that it’s a String, not a variable reference; that’s because it’s not possible (for me) in Unityscript/Javascript to pass variables by reference. However, using Net Reflection techniques you can retrieve a ‘field’ from another Component using literal string.

The third argument is the number of seconds it takes for the timer to end or expire.

The fourth argument is ‘this’, which is the reference to the Component that has instantiated the TimerClass. This Component reference is used to retrieve the field specified in the second argument.

Reflection and SendMessage in action in the UpdateTime() function:

	function UpdateTime(val:float)
	{
		var timerswitch = component.GetType().GetField(switchname).GetValue(component);
		if(timerswitch == true) // if the switch is TRUE
		{
			if(TimeUp() == false) // if the time is not up, then keep on adding time to the counter
				counter += val;
			else
			{
				component.SendMessage(timer_name+"_TimeUp",SendMessageOptions.DontRequireReceiver);
				EndTimer(); // end timer itself
			}
			
		}
	}

This TimerClass has simplified enormously the tracking of timers across the game; I’m glad that I’ve actually started addressing this issue early on, as I know that would just get worse down the line if I didn’t have an elegant solution for it. I’m sure there’s still a lot I could improve, but I feel happy to have made a start.