Friday, December 30, 2011

A Simple C++ Timer Class

I'm still working on my simple game engine for You Are Cat here and there. I'm kind of throwing in features without a definitive design. Many people will tell you that that is a headache and not the way to build an engine. I would agree, but I tend to learn things a little better when I have to revise and rebuild the code constantly.

Yes, it's not very efficient. Yes, I know how to design and do class diagrams, etc. When I get this basic version done and understand how every little piece works and how to optimize it better, I'll probably redesign it the proper way – which will be easier with all that knowledge (which I don't have yet).

But that's not what prompted this blog entry. I built a simple Timer class and wanted to share it.

Where's My Timer?
Since each game mode in You Are Cat will involve a timer (a countdown, to be specific), I needed a timer that would display when that mode is active. I looked around on the internet, but didn't find anything that really fit my needs, and no one had a straight-forward solution, so I just created my own.

This class actually only tracks the change in time for your countdown (you can also have it count up if you want) – it doesn't control how the time is displayed. You would do that separately in however manner you wish. Currently the time in mine displays as a DirectX Font. I'll probably change it later to a texture / sprite.

The Header
You can find the full code of the header here. The class tracks only a few things:

  float _timeToCount; // core time in milliseconds
  float _incrTime; // time to increment
  bool _countdown; // is the timer a countdown?
  bool _timerOn; // is the timer running?
  int _timeMin; // minute portion of _incrTime
  int _timeSec; // second portion of _incrTime

If you look at the full header code you'll see various functions to Initialize, Update, Start, Stop and ConvertTime. Others check to see if the Timer is running, or what the current/core time is. The only ones not defined in the header are the constructor, destructor, Initialize, Update and ConvertTime.

The Implementation
You can find the full code of the implementation here. The guts of the class are the functions Initialize, Update and ConvertTime.

This function gets the Timer object ready for use. You only have to specify the total time for the timer in milliseconds, along with a boolean value for whether the timer is a countdown or not. Depending on that boolean value, it will set _incrTime accordingly. _timeToCount will always represent the original time you initialize the object to; it doesn't change. It will also call ConvertTime to convert the millisecond value of _incrTime to integer values for minutes and seconds.

This function updates the current value of the timer (_incrTime), using the frame time of your engine. In other words, the difference between the start and end of the previous frame. Your engine will be calculating this since it's needed to update positions of objects every frame so it can render movement properly. Merely pass this frame time (in milliseconds) into the Update function. It will decrement / increment the _incrTime accordingly and update the minutes / seconds with ConvertTime. It also clamps _incrTime if it goes out of bounds (beyond 0 or _timeToCount). This function should be called once a frame, most likely in the section that manages the HUD.

This function does a simple calculation to turn the value passed to it (in milliseconds) into two integers: one for minutes, one for seconds. These are the two values that you can use to feed the display of the timer. They can be accessed via the Min and Sec functions.

Using the Timer Class
In my engine, I've added a pointer to a new Timer object in my HUD class as a private variable. Then I created an accessor function called Countdown, which returns the pointer to the Timer.

After I've created my HUD, the Timer is ready to go. I merely call the following to start and display it:

  _HUD->Countdown()->Initialize(90000.0f, YAC_TIMER_DESCEND);

ShowTimer is a function specific to my HUD. If true, a flag in the HUD class is set and the timer will be displayed on-screen, otherwise not. Next, I call Initialize to set the timer at 90 seconds and descending (I have defined YAC_TIMER_DESCEND as true in another file). Lastly, I start the timer with Start, which sets the _timerOn flag.

Because the timer won't always be displayed, there's no point in wasting clock cycles by calling an update function if it's not being used. So my timer only updates within my HUD class implementation when it's on and running. I call the update when it's time to display the current time of the timer. Here is what I call:

  if (_pTimer->isRunning()) {_pTimer->Update(frameTime);}

_pTimer is the actual private variable for the Timer, the one that was accessed by Countdown in the previous code snippet. If the timer is running, then update it. After that, display it's updated value on the screen using the Min and Sec functions. Once it reaches the end of the countdown (or countup, if that's a word), it will not advance anymore, having been clamped by the Update function.

Once the timer is finished, you'll need code that advances/ends the gameplay, as well as housekeeping function calls that stop, restart, hide or kill the Timer object, depending on your needs.

You Are Cat
Another reminder that the full code I'm working on is visible as an open source project (Eclipse Public License 1.0) on Google Code. You can view it here.

If I make any changes to the Timer class, I'll update this post accordingly. There are different ways it can be implemented, obviously, it just boils down to the needs of your program.

No comments:

Post a Comment