◾ 4.3 Scripts used for spawning ◾ 4.4 A script to set gravity
◾ 4.5 A script that simulates friction ◾ 4.6 Cameras
43 4.2 The Timer Class
◾ 4.8 Automatic gameObject self-destructor ◾ 4.9 Object spinner
◾ 4.10 Scene manager
4.2 The Timer Class
Our timer system will be named TimerClass.cs and the full script looks like this:
public class TimerClass {
public bool isTimerRunning= false; private float timeElapsed= 0.0f; private float currentTime= 0.0f; private float lastTime= 0.0f;
private float timeScaleFactor= 1.1f; // <-- If you need to scale
// time, change this!
private string timeString; private string hour; private string minutes; private string seconds; private string mills;
private int aHour; private int aMinute; private int aSecond; private int aMillis; private int tmp; private int aTime;
private GameObject callback;
public void UpdateTimer () {
// calculate the time elapsed since the last Update() timeElapsed=Mathf.Abs(Time.realtimeSinceStartup-lastTime);
// if the timer is running, we add the time elapsed to the // current time (advancing the timer)
if(isTimerRunning) {
currentTime+=timeElapsed*timeScaleFactor; }
// store the current time so that we can use it on the next // update
lastTime=Time.realtimeSinceStartup; }
public void StartTimer () {
// set up initial variables to start the timer isTimerRunning=true;
lastTime=Time.realtimeSinceStartup; }
public void StopTimer () {
// stop the timer isTimerRunning=false; }
public void ResetTimer () {
// resetTimer will set the timer back to zero timeElapsed=0.0f;
currentTime=0.0f;
lastTime=Time.realtimeSinceStartup; }
public string GetFormattedTime () {
// carry out an update to the timer so it is 'up to date' UpdateTimer(); // grab minutes aMinute=(int)currentTime/60; aMinute=aMinute%60; // grab seconds aSecond=(int)currentTime%60; // grab milliseconds aMillis=(int)(currentTime*100)%100;
// format strings for individual mm/ss/mills tmp=(int)aSecond; seconds=tmp.ToString(); if(seconds.Length<2) seconds="0"+seconds; tmp=(int)aMinute; minutes=tmp.ToString(); if(minutes.Length<2) minutes="0"+minutes; tmp=(int)aMillis; mills=tmp.ToString(); if(mills.Length<2) mills="0"+mills;
45 4.2 The Timer Class
// pull together a formatted string to return timeString=minutes+":"+seconds+":"+mills;
return timeString; }
public int GetTime () {
// remember to call UpdateTimer() before trying to use this // function, otherwise the time value will not be up to date return (int)(currentTime);
} }
4.2.1 Script Breakdown
In this script, we will only update time whenever the time is requested. Although there may be cases where the timer would need to be updated constantly, in the projects for this book we only need to do it on demand. So, after the variable declarations, the TimerClass. cs script begins with an update function called UpdateTimer(). Note that if you wanted the timer to update constantly, you would derive the class from MonoBehavior (instead of from ScriptableObject as it currently does) and add a call to UpdateTimer in your main Update function.
The timer works by having a variable called currentTime that stores the amount of time elapsed since the timer started. currentTime starts at zero, then UpdateTimer() cal- culates how much time goes by between updates and adds it to currentTime. The value of currentTime is then parsed into minutes, seconds, and milliseconds, and returned as a nice, tidy formatted string in the GetFormattedTime() function of the same class.
UpdateTimer() will be the only function that updates the timer’s time system:
public void UpdateTimer () {
// calculate the time elapsed since the last Update() timeElapsed=Mathf.Abs(Time.realtimeSinceStartup-lastTime);
A variable called timeElapsed tracks how much time has gone by between updates. Time.realtimeSinceStartup is used for good reason. By using realtimeSinceStartup, the game can do whatever it likes to the Time.timeScale value (speeding up or slowing down Unity physics updates), and realtimeSinceStartup will still provide usable values. If Time. time were used, it would be affected by the timeScale and would fail to provide real-time values if its value were set to anything other than 1.
// if the timer is running, we add the time elapsed to the // current time (advancing the timer)
if(isTimerRunning) {
currentTime+=timeElapsed*timeScaleFactor; }
// store the current time so that we can use it on the next // update
lastTime=Time.realtimeSinceStartup; }
The rest of the function checks to see whether isTimerRunning is true before updat- ing currentTime. isTimerRunning is a Boolean that we can use to start or stop the timer without affecting anything else.
Note that one commonly used method of pausing Unity games is to set Time.timeScale to 0, which would stop a timer that didn’t use Time.realtimeSinceStartup. In this case, we will be unaffected by timescale, so this alternative system will need to be used to start and stop the timer during a game pause.
The final part of the UpdateTimer() function grabs the current Time.realtimeSince- Startup and stores it in the variable lastTime, so that we can use its value to calculate the time elapsed between this and the next call to UpdateTimer.
A StartTimer() function is used to start the timer:
public void StartTimer () {
// set up initial variables to start the timer isTimerRunning=true;
lastTime=Time.realtimeSinceStartup; }
isTimerRunning tells us whether or not to update currentTime in the UpdateTimer() function shown earlier. When the timer starts, we need to ensure that its value is true.
lastTime needs to be reset when we start the timer so that time will not be counted that occurred ‘in between’ the timer being stopped and the timer starting up again.
public void StopTimer () {
// stop the timer isTimerRunning=false; }
isTimerRunning is set to false, which stops UpdateTimer() from adding any extra time to the currentTime variable.
If there is ever a need to reset the timer, we need to refresh some of the main variables to their default states. In the ResetTimer() function, timeElapsed, lastTime, and currentTime are reset:
public void ResetTimer () {
// resetTimer will set the timer back to zero timeElapsed=0.0f;
currentTime=0.0f;
lastTime=Time.realtimeSinceStartup; }
47 4.2 The Timer Class
We reset lastTime to the current time taken from Time.realtimeSinceStartup, which effec- tively removes the time counted between now and the last update and starts counting from now instead. Finally, we make a quick call to UpdateTimer() to start the timer process again.
Whenever we need to display the time on the screen, it is most likely that we will need it to be formatted in an established format such as minutes:seconds:milliseconds. To do this, a little work is required to calculate the required units from our currentTime vari- able, as currentTime is simply a float value containing a number that bears no resemblance to what we need. Time.realtimeSinceStartup returns time as reported by a system timer in seconds. The GetFormattedTime function takes this value and breaks it up into the units we need, then puts together a nicely formatted string and returns it.
public string GetFormattedTime () {
// carry out an update to the timer so it is 'up to date' UpdateTimer();
Note that when GetFormattedTime() is called, we first make an UpdateTimer call to update the currentTime value. As mentioned earlier, the timer does not update itself—it is a lazy updater in that it only updates when we ask it to do something. In this case, we ask it for a formatted time string.
From there on, we are simply doing the math to get the minutes, seconds and mil- liseconds values from currentTime:
// grab minutes aMinute=(int)currentTime/60; aMinute=aMinute%60; // grab seconds aSecond=(int)currentTime%60; // grab milliseconds aMillis=(int)(currentTime*100)%100;
After minutes, seconds, and milliseconds values have been calculated and stored into the integer variables aMinute, aSecond, and aMillis, three new strings called seconds, minutes, and mills are built from them:
// format strings for individual mm/ss/mills tmp=(int)aSecond; seconds=tmp.ToString(); if(seconds.Length<2) seconds="0"+seconds; tmp=(int)aMinute; minutes=tmp.ToString(); if(minutes.Length<2) minutes="0"+minutes; tmp=(int)aHour; hour=tmp.ToString(); if(hour.Length<2) hour="0"+hour;
tmp=(int)aMillis; mills=tmp.ToString();
if(mills.Length<2) mills="0"+mills;
The function uses the .Length of each string to discover whether or not an extra ‘0’ should be prefixed to the time value. This is purely for aesthetics, making the time strings consistently have two numbers even when its value is less than 10.
The final string is composed of a colon separator between each time value and then returned like this:
// pull together a formatted string to return timeString=minutes+":"+seconds+":"+mills;
return timeString; }
At the very end of TimerClass.cs, a GetTime() function provides a way for other scripts to process the value of currentTime:
public int GetTime () {
// remember to call UpdateTimer() before trying to use this // function, otherwise the time value will not be up to date return (int)(currentTime);
}
An example of how GetTime() may be used can be found in the Tank Battle game source code provided with this book (http://www.crcpress.com/product/isbn/9781466581401), where a game controller script takes the return value from a timer’s GetTime() function and checks it to see whether the game has been running long enough to end.