Sign in to follow this  
suliman

Framerate-indepentant friction?

Recommended Posts

suliman    1653

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

Edited by suliman

Share this post


Link to post
Share on other sites
suliman    1653

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?

Share this post


Link to post
Share on other sites
Juliean    7077


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?

Share this post


Link to post
Share on other sites
Erik Rufelt    5901

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;
  }
}

Edited by Erik Rufelt

Share this post


Link to post
Share on other sites
HappyCoder    5053
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. Edited by HappyCoder

Share this post


Link to post
Share on other sites
Norman Barrows    7179

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.

Edited by Norman Barrows

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this