0
\$\begingroup\$

I'm getting to the part in development where I'm noticing that timing is going to be an issue.

If I put my movement update in the same function where I draw the scene, then a low FPS means slower movement and a high FPS means very fast movement. But putting it in its own function that is called every 1/60th of a second still has problems. I'm starting to realize that there is no way you can rely on a scheduled function to keep track of time. It is just way too unreliable.

But I still need to be able to move at the same speed regardless of the FPS that a computer can handle. So what is the best way to keep track of time and move around?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ To add to the other answers - use a timer that measures elapsed time and take the delta between updates, but be careful when choosing this timer. Timers based on the "wall clock" (the time you see in the task bar) are notoriously non-monotonic (and low resolution). Make sure you account for the rare possibility of returned time values being in the past (e.g. if the operating system re-syncs the time and finds it was a few seconds fast). Some timers guarantee monotonic non-decreasing behavior (time never goes backwards), but don't expect it unless your API explicitly states this. \$\endgroup\$ Commented Jan 1, 2015 at 16:02

3 Answers 3

2
\$\begingroup\$

Well, I am not sure what language you use for your game so I'll explain it in C++, but you could use something called 'deltatime'

Uint32 last = 0;
Uint32 delay = 0;

void loop()
{ 
    Uint32 now = SLD_GetTicks();

    if(now > last)
    { 
        delay = now - last; 
        last = now; 
    }

    moveUp(delay); 
}

void moveUp(Uint32 delay) 
{ 
    positionY += speed * delay; // This lowers or highers the speed depending on the delay.
} 
\$\endgroup\$
1
\$\begingroup\$

This is how I do it in iOS games:

// get's called approx every 60th of a second but not always
- (void)drawViewLoop
{
    timeThisRound = CFAbsoluteTimeGetCurrent();
    deltaTimeThisRound = timeThisRound-lastTime;
    // don't let the delta get too big.  Even if the fps slows way down cap delta at 1/20th of a second
    if (deltaTimeThisRound > 0.05) {
        deltaTimeThisRound = 0.05;
    }
    [self drawScene];
    // present screen
    [self updateScene];

    lastTime = timeThisRound;
}

I usually don't let my delta get huge. Let's say some system thing happened, they put the app in the background, or whatever. If it's larger than .05 then I let things start dragging because to me that's better than having time jump forward 3 or 4 seconds and your ship blows up. Also a deltaTimeThisRound of say 3.0 would mess up all the physics math.

Some of my animations are frame based. So no matter how fast things are progressing it will show all N number of frames of that animation. For those each time I hit drawViewLoop I increment the frame of the sprite that you see.

Some of my animations are time and percentage based. Where p % through the move is calculated by taking timeStart of the move, duration of the move, and timeThisRound - timeStart to get a time from the start of the move. So p = timeThrough / duration with some clamping and completion handling on 0 and 1.0.

Some of my animations are physics based where position += velocity * deltaTimeThisRound. These are the ones that are effected by clamping my delta at .05.

\$\endgroup\$
1
\$\begingroup\$

Any answer that doesn't link to Glenn Fielder's Fix Your Timestep article isn't an answer at all. So first, read that, because it more than addresses your problem. Note that you do not have to implement his ultimate solution in order to have a reasonably well behaved simulation.

Yes, you can use a raw delta time, clamped or otherwise, as other answers have suggested, but this will ultimately lead to inconsistent simulations due to the inherently unpredictable fluctuation of the time between frames.

The root of the issue is that you are essentially utilizing Euler's method to solve an ordinary first order differential equation for x when you do this:

x = x + delta * rate

Aside from the fact that Euler's method isn't the best approximation of the actual solution, it's generally OK as long as delta is the same every time. If it's not, then your simulation will not be deterministic, or worse, completely screwed when you pass in some bonkers delta that sends your object through a wall.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .