Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

What is the suggestion of "enough precision" in a timer for a fixed game update loop? Currently I'm testing with this code, but it sometimes misses 1-2 updates @ 50hz. While at 30hz it seems to work perfect. 60hz again is even worse than 50hz. Is this because I have too low resolution on the timer? Is there something I'm missing?

share|improve this question

3 Answers 3

up vote 2 down vote accepted

There is a wrong assumption behind this question which leads to a solution that is not well prepared for real world requirements.

Don't ever count on a consistently stable frame time X, unless you are on a Real Time Operating System. The usual gaming platforms don't fall under this category. On all other systems the frame time is not deterministic (even if your update loop were deterministic, which it isn't either), it depends on variables that the game cannot control, the OS scheduler for one thing, other processes can kick in, energy saving settings and lots of other things.

Having that out of our way, the first and most important conclusion is: The game has to deal with a varying frame time. It might be 16 ms in one frame, and 27 ms in the next. The update loop simply has to deal with it. That rules out the fixed dt value in your code example.

So what is the solution?

Basically there is only one relyable and reasonable source of game time, the refresh rate of the graphics device. It does not make sense to update the game state with a higher frequency than the graphics card can render it. In fact that would introduce new problems without any reasonable gain.

However, it makes sense to update some subsystems with a higher frequency, as a physics engine for instance needs a stable simulation time. Most physics engines handle this theirselves by adding sub-steps/sub-loops, for instances bullets btDynamicsWorld::stepSimulation(btScalar timeStep,int maxSubSteps, btScalar fixedTimeStep) needs only be called once in your game loop and handles the necessary substeps itsself. The first parameter timeStep is the real dt since the last frame. The third parameter fixedTimeStep is the fixed simulation time, so it will step the simulation by adding substeps of fixedTimeStep until it hits the real frame time (timeStep) and even interpolates the physics state to the exact frame time. So that dirty work is off your shoulder unless you implement your own physics system.

So at the end it is much simpler and does not need any timers at all, except vsync to wait for the graphics cards swapping. Other than that, just measure the time since the last swap, that is the frame time to be passed to the game's subsystems.

share|improve this answer

The precision should be precise enough to meet your requirements. Your requirements may allow for some missed updates now and then. Your requirements may allow only high-end hardware.

It's up to you to find the balance between resource usage and precision. The precision will vary from genre to another, from one game to game and even from one game mode to the next.

In this case, if you don't have any other problems with setting the precision at 30Hz, then set it at 30Hz.

share|improve this answer

I see several issues with your code:

  • First, your update loop never sleeps, it just busy-waits until enough time has passed. While this shouldn't actually cause any problems in your example (other than possibly overheating your CPU), it would be a problem if you wanted to do anything useful in some other thread at the same time. Also, it's just plain silly. A much better solution is to calculate the time at which the next update should happen and, if that time has not yet passed, sleep until it has.

  • Second, you seem to be relying on Thread.Sleep() being accurate, and on Thread.Abort() immediately stopping the thread no matter what. These are both bad assumptions. Instead, if you want the thread to stop exactly after a given amount of time, let the thread itself figure out when to do that (since it's already timing itself) and call Thread.Join() to wait until the thread exits. (In fact, for this simple example, you don't really need to spawn a separate thread at all, since all your main thread does is sleep anyway.)

  • Also, you're storing your timestep as a whole number of millisecond. This is a problem because you cannot, for example, accurately represent 1/60 of a second that way. Indeed, with integer arithmetic, 1000 / 60 = 16, while 1000 / 16 = 62, so, even if it worked otherwise exactly as intended, your update loop would run 62 times per second, not 60.

    A simple solution here is to store the timestep (and the target time for the next update) as a floating point value. That's still not exact, but it's much more accurate than an integer value. Alternatively, you don't really need to store the timestep at all if you simply calculate the target time by multiplying the number of updates executed so far by 1000 and dividing it by the desired update frequency per second.

The following code snippets demonstrate these two approaches. This one uses a floating-point timestep (demo on ideone):

double dt = 1000.0 / 60;
double targetTime = 0;
int i = 1;

while (targetTime + dt/2 < 1000)
{
    long currentTime = sw.ElapsedMilliseconds;
    if (currentTime < targetTime)
    {
        Thread.Sleep((int) (targetTime - currentTime));
    }
    else if (currentTime > targetTime + 100)
    {
        targetTime = currentTime;  // we're too late, give up
    }

    Console.WriteLine("Update " + i + " at t=" + sw.ElapsedMilliseconds + " (target=" + targetTime + ")");
    i++;
    targetTime += dt;
}

while this one recalculates the target time directly from the desired frequency and the number of updates using integer arithmetic (demo on ideone):

int freq = 60;
int maxSlip = 100;  // give up if we're more than 0.1s late

for (int i = 0; i < 1*freq; i++)
{
    long currentTime = sw.ElapsedMilliseconds;
    long targetTime = (1000 * i) / freq;
    if (currentTime < targetTime)
    {
        Thread.Sleep((int)(targetTime - currentTime));
    }
    else if (currentTime > targetTime + maxSlip)
    {
        i = (int)( (double)currentTime / freq + 0.5 );  // we're too late, give up
    }

    Console.WriteLine("Update " + i + " at t=" + sw.ElapsedMilliseconds + " (target=" + targetTime + ")");
}

One detail worth pointing out is the + dt/2 in the terminating condition of the first snippet, which ensures that we stop as soon as the target time is approximately 1000 (or as close to it as we can get using increments of dt), even if floating point roundoff might cause it to actually be something like 999.99999999.

Also note that neither of the demo programs actually spawns a separate thread. If you do want to do that (e.g. to carry out something else while the loop runs), you can just replace the direct call to FixedLoop() with:

Thread t = new Thread(FixedLoop);
t.Start();
t.Join();  // wait for the thread to end
share|improve this answer
    
The thread was for a simple test purpose which I threw togheter real quick. The problem isnt the threading, or what do to when not simulating physics, etc - the problem is how to game loop is best implemented. Didn't mark your as the answer cause of to much info about other things. No offense! –  hayer Feb 20 '13 at 20:10

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.