Game Timing

Started by
6 comments, last by NEXUSKill 11 years, 10 months ago
Hi,

I'm a student developer and I had a question for everyone regarding the best practices for timing things in-game.

Say, for example, that I had a heal button which heals the player-character. There are to be n milliseconds between when the heal button was last pressed, and when it's available to be pressed again.

In my last project, I simply created an int for each cooldown effect which gets set to n milliseconds and decremented every tick while it's greater than 0. If it's less than 0, that power is available again. This method, though, makes a lot of assumptions about the clock rate of the computer running the program. Can someone point me toward some reading or explain a better solution for timing things in-game?
Advertisement
Why not get the system time, in milliseconds?
So, when you hit the heal button, you store the current milliseconds + the time before the next heal can be used as the cooldown timer. Then, you just check if the current time has past the stored cooldown time. If it hasn't, then you can't heal.

Be sure to use an unsigned int (or, uint32_t)

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

Going off of what BeerNutts said, here's how you can get the current time from the start of the executable in millaseconds, taking into account clock speeds:
unsigned int RunTime()
{
//CPU "ticks" since the program started.
clock_t programTickCount = clock();

//Conversion rate between ticks and millaseconds.
float msMultiplyer = 1000.0f / CLOCKS_PER_SEC;

//Convert from ticks to seconds.
int millaSeconds = (programTickCount * msMultiplyer);

return millaSeconds;
}


Sometimes, if you don't need accuracy, it's nicer to deal with the number as a float where 1.0f equals 1 second.
//The time, in seconds, since the program started. (1.5f = one and a half seconds)
float RunTimeInSeconds()
{
//CPU "ticks" since the program started.
clock_t programTickCount = clock();

//Convert from ticks to seconds.
float seconds = float(programTickCount) / CLOCKS_PER_SEC;

return seconds;
}


This is standard C++, requiring no external APIs. clock(), clock_t, and the CLOCKS_PER_SEC #define are all contained in the standard <ctime> header (From the old C standard library, I guess).

This gives millasecond ([size=2]1/1000 of a second) accuracy, which is plenty fine for my needs. Some people need microsecond ([size=2]1/1000,000[size=2] of a second) accuracy depending on their projects, and then you have to go into non-standard APIs to get that.
First of all: is your game trying to run at a fixed framerate or at a variable framerate?

If the former, whatever controls the framerate will just tell the game to execute multiple logic frames if it's going too slow (and to do nothing if it's going too fast). In this case you can easily just keep using your current method (albeit counting frames instead of milliseconds), since your game logic doesn't care.

If the latter, you'll need to keep track of when the cooldown started and then compare it against the current time. Use the difference to know if the cooldown expired or not (and if not, how much time is left before it expires).
Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.
What I do is each of my game objects can register a delegate/functor with a global time manager, and each frame every object that registered for time events gets a callback with the time elapsed since the last update. I use a floating point number to express the time elapsed in seconds for clarity.

So for your case I would have something like this:


void HealButton::onClick()
{
heal();
startCooling(_timeToCool);
}

void HealButton::onTime( F32 timeDelta )
{
if (isCooling())
{
_coolTimeRemaining -= timeDelta;
if (_coolTimeRemaining < 0)
{
_coolTimeRemaining = 0;
stopCooling();
}
}
}

Clarity:

that should be if (_coolTimeRemaining <= 0){ etc... }
Thank you for the replies, everyone!


[background=rgb(250, 251, 252)]So, when you hit the heal button, you store the current milliseconds + the time before the next heal can be used as the cooldown timer. Then, you just check if the current time has past the stored cooldown time. If it hasn't, then you can't heal.[/background]





That's a good idea, and it's much simpler than the way I was doing it. I'll have to use this method from now on instead of my silly decrementation method.


First of all: is your game trying to run at a fixed framerate or at a variable framerate?


This was more of a general best-practices question than relating to a specific example, but thank you for the explanation regarding the differences smile.png


What I do is each of my game objects can register a delegate/functor with a global time manager, and each frame every object that registered for time events gets a callback with the time elapsed since the last update. I use a floating point number to express the time elapsed in seconds for clarity.


This answer touches more on what I was thinking about when I asked the question. I've gotten into the practice of using managers (input manager for handling keyboard events, image manager for asset IO, etc). That got me wondering if people knew of any good patterns or code structures (i.e. timing manager) that would be good for handling cooldowns (or any timing-related problem, like length of time for a camera to pan during a cinematic, or something), and what functions or methods a utility timing class would have.
The best way to make 0 assumptions is to remember what time it was the last time you updated your game state and what time it is when you start the new update.
Any time based logic then will ask for the difference between the two times, this will give out reliable results regardless of the processor speed and application performance.

It also makes any cinematic (in the meaning of physics, not cinematic videos) formula, like speed based movement or acceleration will have the Delta Time available to provide accurate results.
Game making is godlike

LinkedIn profile: http://ar.linkedin.com/pub/andres-ricardo-chamarra/2a/28a/272


This topic is closed to new replies.

Advertisement