In this lecture, we'll learn how to use the selection control structure to implement
a timer component and you will discover yourself
using timers regularly throughout the games you write,
it's a really useful thing to have.
Given that claim, when might we want to use a timer?
Well, if we have levels in our game that have a time limit,
we can use a timer to determine when the level has ended.
We can use a timer to decide when to spawn new objects into the game world.
We can use a timer if our game objects have
a limited lifespan so this is really a death timer.
We can decide when to destroy that game object
and we might even decide if we're going to regularly or
periodically increase the difficulty of our game
at particular time hacks than using a timer to determine
when to increase that if difficulty is a really useful use of
a timer component and you'll probably come across
other applications of a timer component as well.
So, first, you should do an in-video quiz about timers and now,
we should go look at how those timers can be
implemented using the selection control structure.
This is the timer component that we're going to look at and we'll start with the fields.
We have total seconds that tells how long the timer will run when we run it.
We have two fields that support the execution of the timer.
We have elapsed seconds that will tell us
how long the timer has been running since it was started,
and we had this Boolean variable or field called running that we
started false and that tells us whether the timer is currently running.
We also have a Boolean field called started that we also start as false,
and we'll talk about why we need that when we talk about the finished property.
Running and started, sort of keep track of the state of the timer so we regularly call
those kinds of Boolean fields
flags so I will probably call them flags throughout this discussion.
Before we look at the properties,
let's look at the methods.
Starting with the run method,
and the run method gets called when the consumer of
the class wants to start running the timer.
I did not call this method start because as you know,
we always get a start method that has a different meaning in
the scripts we create so using a different name makes a lot of sense.
We only run the timer if total seconds is greater than zero.
If it's currently zero or, heaven forbid,
it's negative, there's no reasonable way to run the timer so we don't bother.
This if statement here is to check whether we should actually run the timer,
given the value of the total seconds variable.
If we should run the timer,
we set the started flag to true because we did just start the timer.
We set the running flag to true because the timer is currently running,
and we set elapsed seconds to zero because for this run of the timer,
no time has elapsed yet.
In the update method,
which remember gets called every frame,
we first check to see if the timer is running
because we're going to do some math and some checking down here,
but that math and checking is only appropriate if the timer is currently running.
If the timer is not running right now,
we don't have to do anything.
This if statement is for efficiency.
If, in fact, the timer is currently running,
the first thing we do is,
we take elapsed seconds and we add to it that's what plus-equal does,
time.deltaTime, and time.deltaTime tells
us how much time it took the previous frame to execute.
So, essentially, this is ticking the timer up
by however long the previous frame took to run,
and then, we can check to see if
elapsed seconds is greater than or equal to total seconds.
We definitely don't want to just check equal because if we check equal,
it's entirely possible that we'll jump over total seconds by a tenth of a second,
or a hundredth of a second,
or something and then,
we did never realize we were done,
so we check greater than equal to here.
If the elapsed seconds is greater than
equal to however long the timer is supposed to run,
we start running to false because we're no longer running.
Let's go take a look at the properties.
We have a number of properties here.
We have the duration property so
the consumer of the class would use this to set the duration of the timer.
The timer can only be set if it's not currently running.
It doesn't make sense to be able to change the timer while it's running.
This is a validation check to make sure that we should pay
attention to what the consumer of the class is trying to do with the duration,
but if it's not running,
we'll just set total seconds to whatever value they are assigning the property to.
For example, on the consumer side,
I'm going to jump over to a timer test so setting the duration property looks like this.
We have a timer object,
we access its property using dot and property name and then to set that property,
is just like an assignment for a variable.
We say equal and we provide whatever value we want to set the duration to be.
When we get over here,
that duration will go into the total seconds variable.
This property, returns a Boolean.
It tells whether or not the timer is finished.
And that's really important to us.
We're going to run timers and we're going to need to know when they're
done so that we can spawn something,
or end the level,
or variety of different things.
So we need to know when the timer is finished.
Notice, that there is a Boolean expression here that is
the value that's going to get returned when someone tries to read the finished property.
Boolean expressions are not just for when
we need a Boolean expression in an if statement,
we can also use them to come up with a true or false value.
The timer is finished if it's already been started and it's not running.
The reason we need these started field or flag,
is because we can't just check not running because when we
create the timer object before doing anything with it, it's not running.
We would say, "Oh,
it's finished already," even though we never even started it.
That's why we need the two flags,
the started flag and the running flag.
Running gives the simplest of all,
it just returns running.
I do have code over here,
the timer test that we've already looked at a little bit,
and I commented in the previous module that we don't really use
instantiation to create objects from the script classes,
instead we get objects from the script classes when
we add components to a particular game object.
For the first time ever,
you will now see that I am actually dynamically,
from within a script,
adding a component to the game object that this timer test script is attached to,
so I can, on the fly,
add components to or remove components from game objects and so here,
in timer test, I'm adding a timer.
This will be attached to the main camera and so it
will add a timer component to the main camera.
It will set restoration to three and it will run.
And it saves the start time because there's some bookkeeping here.
Here's why access the timer finished property and so,
once the timer is finished,
I'm going to calculate the elapsed time and then print that
out and I'll save the start time and restart the timer.
I'm going to run the timer a number of times and I'm going to
print how long it ran each time.
Let's go see how all this works in the unity editor.
As you can see, my main camera object has the timer test script attached and so,
when I run the game,
you can see that it actually dynamically added
a timer script and there's the timer running for approximately three seconds each time.
Now that's approximate because, like I said,
we're probably not going to hit three seconds exactly,
so it's pretty close but not perfect.
To recap, in this lecture,
we learned how we can use the selection control structure to implement a timer component.