Framerate-indepentant friction?

Started by
6 comments, last by suliman 8 years, 6 months ago

Hi

In many cases i need to use some sort of "friction", such as air-drag on airplanes, brakes in a car game etc.

Typically you do this like:


speed = speed*0.98;

The problem is, if i place this in my main update loop (i let my game update "once per tick") this is NOT framerate independant. If FPS goes up or down in my game, the brakes on the car will be of different efficency... How do I solve this? (assume deltaTime is known, ie the time for a single game-tick).

Thanks!
Erik

Advertisement

This is often solved by always using the same frame-rate in calculation, Google for "fix your timestep" or "fixed timestep gameloop" and you should find many links on this site alone, as well as others.

So basically decide to always run your physics update at 60 updates per second or 100 updates per second or whatever makes sense and gives you good results and good performance.

well that would require me to rework my entire game as i have not a single physics function seperate from everything else. Not worth it just for friction.

Is there no other way? I can do i for-loop, applying friction an amount of times corresponding to the deltaTime, like this:


float s=deltaTime*1000;

for(int i=0;i<s;i++){
   speed = speed * 0.999;
}

Its just not very exact. Any more clever solution?


well that would require me to rework my entire game as i have not a single physics function seperate from everything else. Not worth it just for friction.

Having a fixed timestep is totally worth it, and unless you want to apply the last step mentioned in the "fix your timestep" article about interpolating between current and last state, doing so is extremely easy - you literally just need to modify your game loop as mentioned in the article, thus separate rendering and state update. I would give it a try eigther way.

If this is not an option, I think I remember being given a similar solution for performing HDR adaptation in a shader:


float fNewAdaptation = fPreviousLum + (fCurrentLum - fPreviousLum) * (1 - exp(-dt * 0.98));

I'm way too tired to reformulate this, but I think this should do the same thing you search for, where "dt" is the timestep since last frame, you/someone else/me once I got some sleep just needs to change it fit your friction formula... don't know, maybe just multiply the last term with your speed?

You can fix the timestep just for that friction calculation.

(Note that over time this practice tends to add up so after a while you have 1000 local versions of what should be done in exactly one place at the outer game-loop, but if you just have a few things in an already working game it works. I speak from personal experience, as I have used this method too many times. smile.png Though that said when it comes to time-intervals like this there are often several places other than physics where this method is simple and effective, as the time-interval could be for example spawning particles or weapon-delay or whatever, but for physics it really should not be local to individual objects.)

Assuming you have something like this right now:


struct Car {
  float speed;
};

void breakCar(Car &car, float dt) {
  car.speed = car.speed * 0.98;
}

Change it to:


struct Car {
  float speed;
  float breakTime;
};

void breakCar(Car &car, float dt) {
  const float breakInterval = (1.0f / 60.0f);

  car.breakTime += dt;
  while(car.breakTime >= breakInterval) {
    car.speed = car.speed * 0.98;
    car.breakTime -= breakInterval;
  }
}

Use the pow function to calculating how much damping to apply over time (I assumed c++)
speed = speed * pow(dampingPerSecond, secondsFromLastFrame);
Note that pow isn't super cheap computationally but you shouldn't worry about the performance of it unless you are calculating the damping of many objects and you found it to be a bottleneck.

As others have suggested, you can fix your timestep. If you do, then you can calculate the damping per from once and store it in a variable for reuse.
My current game project Platform RPG

the fundamental problem, as already mentioned, is that you do not run update at a fixed speed, IE some fixed number of updates per second.

this is caused by using a standard game loop running at whatever speed it runs at on your PC.


This is often solved by always using the same frame-rate in calculation, Google for "fix your timestep" or "fixed timestep gameloop" and you should find many links on this site alone, as well as others.


well that would require me to rework my entire game as i have not a single physics function seperate from everything else. Not worth it just for friction.

Is there no other way?

there are actually TWO ways to get a fixed update speed.

the first, as already mentioned, is to "fix your timestep" as explained in Gaffer's article online. this algo passes render ET into the update functions, which then "consume" it in specific DT sized chunks of time. both current and previous state are stored, and render does a tween between previous and current states when drawing. the result is render runs as fast as possible, and updates run at a specific speed, such as 30Hz. but as you say,this requires a bit of modding to an already existing game. the algo also needs to include code to handle long render times to avoid becoming un-play-ably unresponsive under heavy graphics load.

the second method is used to keep basic game loops from running too fast on faster PCs. this is the framerate limiter method. this algo uses a timer to time the duration of a single main game loop iteration. at the end of the main loop, it goes into a loop and waits until a specified amount of time has passed since the start of this iteration of the main game loop. so lets say you want to run at 60fps, which means update at 60Hz in a standard game loop. so you do something like this:

while !quitgame

start_timer

process_input

update_all

render_all

while(elapsed_time<15ms)

{

// do nothing

}

}

decide what your desired FPS/update Hz is, and set your framerate limiter time appropriately.

i find this method much easier to implement than "fix your timestep". another advantage is has over "fix your timestep" is that it automatically degrades gracefully under heavy graphics load, without the need for special code to handle long render times.

the downside is that render wont run as fast as possible, so you may surrender some smoothness in animations, depending on the difference between the limited and unlimited frame rates.

three approaches are possible for selecting the limited rate:

1. at the unlimited rate on the target PC. faster PCs will run at the same rate. slower PCs will runs slower. heavy graphics will cause momentary noticeable slowdowns on the target PC.

2. somewhat below the unlimited rate on the target PC. faster PCs will run at the same rate. much slower PCs will runs slower. the heaviest graphics will occasionally cause momentary noticeable slowdowns on the target PC.

3. as low as possible while maintaining sufficient responsiveness on the target PC. basically you run the game as slow as you can. almost all PCs will run at the same speed. even the heaviest graphics will almost never cause slowdowns on the target PC. good for games with complex update methods - leaves more time for simulating everything.

can also be good for games with occasional heavy graphics. a slower but stable framerate is sometimes preferable to a faster but spikey framerate.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

yeah i might need to limit higher framerates anyway.

Anyone sees any problem with using pow() as described by HappyCoder? Seems easy enough to do.

This topic is closed to new replies.

Advertisement