🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

fully tweakable framerate-independent movement

Started by
4 comments, last by raigan 3 years, 10 months ago

I've always used a fixed timestep for physics, and I think I have a pretty good understanding of the basics.

However, something I don't see addressed in any articles is how to program things in a timestep-agnostic way, such that you can change the fixed timestep value during development and still have everything moving along the same curves.

Let's say I have the following example code for moving a platformer character; I've tried to include the full range of tools needed for movement: velocity, acceleration, and damping. This is written assuming it will be called at a fixed frequency:

run_speed = 2;      //velocity
brake_decay = 0.95; //viscous damping/exponential decay
gravity = 1;        //acceleration

if(button_pressed)  vel_x = run_speed;
else                vel_x *= brake_decay;

vel_y += gravity;

pos_x += vel_x;
pos_y += vel_y;

If my fixed timestep is currently A ms/tick, and I want to switch to a timestep of B ms/tick, AFAICT I need to calculate three new scaling factors, something like:

run_speed = 2*A_to_B_vel;       //velocity
brake_decay = 0.95*A_to_B_damp; //viscous damping/exponential decay
gravity = 1*A_to_B_acc;         //acceleration

My question is: what formulas should I use for each scaling factor? And, do I need to modify the rest of the simulation code in any way (eg do “ vel_y += gravity * dt^2 ”), or should rescaling these three factors be sufficient?

(NOTE: I realize that by changing the size of the fixed timestep, the positions of objects won't match exactly (because we'll be sampling a curve at a different frequency); my goal is for the objects to be moving along an identical curve regardless of the sample rate.)

For bonus points: is there any way to implement “bullet time” in such a simulation? More generally, what I'd like is to be able to freely alter the timescale of the simulation without changing the fixed-step size, so that when prototyping I can easily experiment with the speed of the entire world to find what feels best. For example, what do I do if I want to slow everything down by 20% while maintaining identical trajectories for all objects? Intuitively this seems equivalent to my original question, i.e. it's about altering the duration of each tick while maintaining the same trajectory curves.

Hopefully someone can point me in the right direction. About 10 years ago I successfully converted a fixed-step simulation from 40hz to 60hz, maintaining an identical feel, so I know it's possible. In fact, IIRC I asked on these same forums and got a great answer.. sadly with the new redesign, I can't find that thread anymore! So I was hoping someone knowledgeable could shed some light. : )

Thanks!

Advertisement

I mean, even with a fixed timestep I would always just use DeltaTime for calculations. If not for the reason of being able to change the timestep, then just because it makes it easier being able to specify variables like speed. What units do you use ie. use for gravity, “meters per tick”? I'd much rather have meters/second and be able to specify -9.8 instead of having to calculate 0.1633 anyways.

Fair enough – but, given values represented in “units of distance per tick”, how do I then rescale them to get the equivalent movement in “units of distance per ms” that you prefer?

You'd do the opposite of multiplying by your fixed dt (if you have 60FPS now, 1/60):

unitsPerSecond = yourUnits * 60;

Thats simply the invers of multiplying by the fixed “dt”.

And given those units, you can then scale them back to any framerate you want:

unitsPerFixedTick = unitsPerSecond * (1 / FPS);

You can store that factor in a constant that you can use throughout your code (then changing the actual framerate is a matter of changing that constant); or you make a “dt” variable that is passes to the functions that need it.

Sorry, I might not have explained the problem well enough.

The answer I'm looking for should involve calculus: how do I correctly rescale my simulation constants so that the paths generated by the simulation follow the same curve in time regardless of sampling frequency.

Your proposed solution will work only for terms which effect the position linearly, like velocity (i.e what you propose is the correct approach for calculating “A_to_B_vel”).

However, unfortunately such an approach doesn't work for the acceleration ("A_to_B_acc") and exponential decay ("A_to_B_damp") terms, because their effect on the position of the object is non-linear. This implies that the rescaling formulas need to be non-linear.

For the acceleration term, I would expect to see an expression that includes “dt*dt” somewhere in the answer. For viscous drag I'd imagine there's a pow() or something, since the curve is exponential.

This topic is closed to new replies.

Advertisement