Using Timer and Game Loop

Using timer and game loop

You normally don't use conventional timers in games. Games have a very different mechanism for handling their logic and the time that passed, they normally don't work with timers or not in the way you would expect:

Games normally have something called a game loop. Generally speaking it's three main functions that are called one after the other in a loop:

while(running)
{
HandleUserInput();
ChangeWorld();
Render();
}

You get user input, you change the game world accordingly and you draw it to the screen. Now, the faster your computer is, the faster this loop runs. That's good for the graphics (think FPS), but bad for the game. Imagine Tetris where every frame the blocks move. Now I would not want to buy a faster computer, the game would get more difficult that way.

So to keep the game speed constant independent of the power of the computer, the loop considers the time passed:

while(running)
{
var timePassedSinceLastLoop = CalculateTimeDelta();

HandleUserInput();
ChangeWorld(timePassedSinceLastLoop);
Render();
}

Now imagine a cooldown for something in game. The player pressed "a", some cool action happened and although he may press "a" again, nothing will happen for the next 5 seconds. But the game still runs and does all the other things that may happen ingame. This is not a conventional timer. It's a variable, lets call it ActionCooldown, and once the player triggers the action, it's set to 5 seconds. Every time the world changes, the timePassed is subtracted from that number until it's zero. All the time, the game is running and handling input and rendering. But only once ActionCooldown hits zero, another press of "a" will trigger that action again.

The ChangeWorld method includes all automatic changes to the world. Enemies, missiles, whatever moves without player interaction. And It moves based on time. If the enemy moves one square per second, You need to make his coordinate a float and add a fraction of a square every time the loop is run.

Lets say you have 30 fps so your loop runs 30 times a second. Your enemy now needs to move 1/30 of a square each loop. Then it will in the end have moved one full square per second.

What are advantages of using game loops over Util timer?

A game loop might run as fast as it can, or it might have a rate limit. Your example seems to be rate-limited, but it's a busy wait loop. It recalculates delta as fast as it can, and then calls Update and Render when delta reaches a certain value. This is inefficient.

Timer is a little bit like your game loop, but more sophisticated. Take a look at the source, particularly the TimerThread class and its mainLoop method. The thread waits on the task queue until the time of the next scheduled task. When a task is inserted, the thread wakes up, performs any tasks that are due, and then waits again until the next task is due.

Game loops are introduced as a concept in many books and tutorials, but there's little or no reason to ever write one yourself. In practice, the main loop is often provided for you by whatever UI or game engine framework you're using. If not, something like Timer may work just fine and save you the trouble of writing it yourself.

Android Game Loop vs Timer

As far as I know there is no difference for simple games. Because GameLoop is actually timer implementation.

How to make timer for a game loop?

You shouldn't try to limit the fps. The only reason to do so is if you are not using delta time and you expect each frame to be the same length. Even the simplest game cannot guarantee that.

You can however take your delta time and slice it into fixed sizes and then hold onto the remainder.

Here's some code I wrote recently. It's not thoroughly tested.

void GameLoop::Run()
{
m_Timer.Reset();

while(!m_Finished())
{
Time delta = m_Timer.GetDelta();
Time frameTime(0);
unsigned int loopCount = 0;

while (delta > m_TickTime && loopCount < m_MaxLoops)
{
m_SingTick();
delta -= m_TickTime;
frameTime += m_TickTime;
++loopCount;
}
m_Independent(frameTime);

// add an exception flag later.
// This is if the game hangs
if(loopCount >= m_MaxLoops)
{
delta %= m_TickTime;
}

m_Render(delta);
m_Timer.Unused(delta);
}
}

The member objects are Boost slots so different code can register with different timing methods. The Independent slot is for things like key mapping or changing music Things that don't need to be so precise. SingTick is good for physics where it is easier if you know every tick will be the same but you don't want to run through a wall. Render takes the delta so animations run smooth, but must remember to account for it on the next SingTick.

Hope that helps.

Handling the game loop with OS timers

Typically, a game will keep drawing new frames all the time even when the user does not do anything. This would normally happen where you have your onIdle() call. If your game only updates the window/screen when the user presses a button or such, or sporadically in between, then MSGWaitForMultipleObjects is a good option.

However, in a continuous-animation game, you would normally not want to block or sleep in the render thread at all if you can help it, instead you want to render at maximum speed and rely on vertical sync as a throttle. The reason for that is that timing, blocking, and sleeping is unprecise at best, and unreliable at worst, and it will quite possibly add disturbing artefacts to your animations.

What you normally want to do is push everything belonging to a frame to the graphics API (most likely OpenGL since you said "any platform") as fast as you can, signal a worker thread to start doing the game logic and physics etc, and then block on SwapBuffers.

All timers, timeouts, and sleep are limited by the scheduler's resolution, which is 15ms under Windows (can be set to 1ms using timeBeginPeriod). At 60fps, a frame is 16.666ms, so blocking for 15ms is catastrophic, but even 1ms is still a considerable time. There is nothing you can do to get a better resolution (this is considerably better under Linux).

Sleep, or any blocking function that has a timeout, guarantees that your process sleeps for at least as long as you asked for (in fact, on Posix systems, it may sleep less if an interrupt occurred). It does not give you a guarantee that your thread will run as soon as the time is up, or any other guarantees.

Sleep(0) under Windows is even worse. The documentation says "the thread will relinquish the remainder of its time slice but remain ready. Note that a ready thread is not guaranteed to run immediately". Reality has it that it works kind of ok most of the time, blocking anywhere from "not at all" to 5-10ms, but on occasions I've seen Sleep(0) block for 100ms too, which is a desaster when it happens.

Using QueryPerformanceCounter is asking for trouble -- just don't do it. On some systems (Windows 7 with a recent CPU) it will work just fine because it uses a reliable HPET, but on many other systems you will see all kinds of strange "time travel" or "reverse time" effects which nobody can explain or debug. That is because on those systems, the result of QPC reads the TSC counter which depends on the CPU's frequency. CPU frequency is not constant, and TSC values on multicore/multiprocessor systems need not be consistent.

Then there is the synchronization issue. Two separate timers, even when ticking at the same frequency, will necessarily become unsynchronized (because there is no such thing as "same"). There is a timer in your graphics card doing the vertical sync already. Using this one for synchronisation will mean everything will work, using a different one will mean things will eventually be out of sync. Being out of sync may have no effect at all, may draw a half finished frame, or may block for one full frame, or whatever.

While missing a frame is usually not that much of a big deal (if it's just one and happens rarely), in this case it is something you can totally avoid in the first place.

Timing animation in (Timer) game loop

Depending on your need you may want to capture current time at last update with DateTime.Now, add 3 seconds and call Update only when it passed:

  DateTime nextUpdateTime = DateTime.UtcNow;

private void gameTick(object sender, System.Timers.ElapsedEventArgs e)
{
if (DateTime.UtcNow > nextUpdateTime)
{
nextUpdateTime = DateTime.UtcNow.AddSeconds(3);
theGame.Update(...);
}
....

Note that if you are planning to debug code you should avoid direct calls to DateTime.Now and figure out how you want time to move while waiting on breakpoint. Check out http://xboxforums.create.msdn.com/forums/p/53189/322422.aspx for discussion on time in games (XNA forum).

Create new enemies by Timer or by game loop?

I recommend a combination: The engine should be driven by "ticks" that in itself don't represent a specific duration. All engine decisions should be done based on time calculations independent of the ticks (e.g. System.currentTimeMillis subtractions). This way when there is high load on the machine you get lower frames per second but the distance of movements is not influenced. When there is lower load you get smoother graphics and movements. You should check for FPS and if they get to high you should even set the thread to sleep or you can generate more enemies. If it gets too low you can lower graphic details or prevent generation of new enemies to adapt to the situation. So I wouldn't start timers but store times for events that you precalculate to occur in the future and check in the game loop if it is time for them to happen (not with exact comparision, of course, but eventtime < now).



Related Topics



Leave a reply



Submit