Framerate independent friction

Started by
35 comments, last by Cornstalks 11 years, 12 months ago
I noticed that my game runs a bit differently when running at 60 FPS on my PC and 30 FPS on my phone, and I traced it down to the friction code. I'm applying friction like this:

newVelocity = oldVelocity - oldVelocity * friction * elapsedTime

The results are not consistent between 60 Hz and 30 Hz. But then I thought about how continuous compound interest is calculated, and I came up with this:

newVelocity = oldVelocity * exp(-friction * elapsedTime)

It works perfectly, at least on paper. Has anyone else ever used an approach like this? Or is there a better way to do it?

Edit: I should mention that the game is using a fixed time step. At 30 Hz it's 1/30 seconds and at 60 Hz it's 1/60.
I like the DARK layout!
Advertisement
I think the better way to do it is to use a fixed time step for physics, independent of how fast the screen updates.

http://gafferongames.com/game-physics/fix-your-timestep/
Personally I think fixed timestep physics is good, but some accomodation for varying time delta is nice because schedulers are never 100% precise.

Personally I think fixed timestep physics is good, but some accomodation for varying time delta is nice because schedulers are never 100% precise.


what do schedulers have to do with a fixed timestep ?

If you use a fixed timestep you won't use elapsed time in the physics calculations.

instead of:

updatePhysics(elapsedTime);

you do:

while (elapsedTime>timeStepSize) {
updatePhysics(timeStepSize);
elapsedTime-=timeStepSize;
}
where timeStepSize is constant so the physics calculations will be deterministics as you always give it the same delta to work with and instead call the physics update routine multiple times per frame if needed (or not at all if your framerate is higher than the physics update rate)
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

It works perfectly, at least on paper. Has anyone else ever used an approach like this? Or is there a better way to do it?


It's the correct way of doing it... You are essentially multiplying with (1-friction) every time step so over multiple time steps the "correction" is (1-friction)^n and not [s]n*(1-friction)[/s] (1-n*friction) as you would get with the first version when increasing the timestep n times.

Edit: n*(1-friction) would be totally off

what do schedulers have to do with a fixed timestep ?


Say for example your physics engine runs at 50Hz, so 0.02s between executing physics. Due to the nature of a multitasking OS it won't be precisely 0.02s every time. One time it might be 0.018, another time 0.023. The difference may not be visible... or it may. Depending upon the nature of the physics and the speed of the objects involved. Also ignoring varying delta would be bad if there was a requirement for repeatability, such as in MMO games.

Using some game platforms the timing variation may be minimal, but some systems that I've tinkered with can have variations of up to 20%.

[quote name='SimonForsman' timestamp='1335678100' post='4935764']
what do schedulers have to do with a fixed timestep ?


Say for example your physics engine runs at 50Hz, so 0.02s between executing physics. Due to the nature of a multitasking OS it won't be precisely 0.02s every time. One time it might be 0.018, another time 0.023. The difference may not be visible... or it may. Depending upon the nature of the physics and the speed of the objects involved. Also ignoring varying delta would be bad if there was a requirement for repeatability, such as in MMO games.

Using some game platforms the timing variation may be minimal, but some systems that I've tinkered with can have variations of up to 20%.
[/quote]

When you use a fixed timestep the delta is constant, you don't pass the actual elapsed time to the physics subsystem. (if you run the physics at 50hz with a fixed timestep you always pass 0.02 as the delta, if the elapsed time is 0.023 you still pass 0.02 as the delta and carry the 0.003 you have left (so the next update triggers after an additional 0.017s have passed), Therefore the scheduler has no impact on the simulation. (You can even run the simulation without measuring the actual elapsed time if the result doesn't have to be displayed in realtime (if you're making a movie for example))

If you need to compensate for a variable delta then you're not using a fixed timestep, you're using a variable timestep.
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

Say for example your physics engine runs at 50Hz, so 0.02s between executing physics. Due to the nature of a multitasking OS it won't be precisely 0.02s every time. One time it might be 0.018, another time 0.023. The difference may not be visible... or it may. Depending upon the nature of the physics and the speed of the objects involved. Also ignoring varying delta would be bad if there was a requirement for repeatability, such as in MMO games.

Using some game platforms the timing variation may be minimal, but some systems that I've tinkered with can have variations of up to 20%.

Pseudo-code for which the scheduler doesn't matter:

float timestep = 1.0f / 30.0f; // 30 updates per second
Clock clock;
clock.start();

while (runMainLoop)
{
if (clock.time() >= timestep)
{
clock.reset();
updateGame(timestep); // use the *fixed* timestep
}

renderGame();
}
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
@Cornstalks: Very true. I wonder whether it might appear inconsistent or stuttery to a player when physics performed is constant but the real-time that it occurs in is not constant, but I really have no proof either way.

@Cornstalks: Very true. I wonder whether it might appear inconsistent or stuttery to a player when physics performed is constant but the real-time that it occurs in is not constant, but I really have no proof either way.

True. In a well done game, the rendering is often interpolated. So you don't just naively call renderGame(), but you give it the system time as well and it interpolates the rendering between the current system time and the game time.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

This topic is closed to new replies.

Advertisement