handmade.network » Forums » Help with framerate independent updates/movement
nyeecola
Italo
9 posts
#11936 Help with framerate independent updates/movement
1 month, 1 week ago Edited by Italo on May 14, 2017, 2:34 a.m.

So, I am creating a game and my current goal is to have it run the same regardless of the framerate it is running at.

I know that a good way to achieve this is to multiply everything that is being updated each frame by a delta_time.

One example of that is here:

1
cooldown += 5 * dt;


I understand that the dt makes it framerate indepedent because it is inversely proportional to how much fps I am running at.

But look at this piece of code for example:

1
2
particle->velocity += particle->acceleration * dt;
particle->pos += particle->velocity * dt;


I've tested it multiple times and it appears to work perfectly in different framerates, but why? I mean, it looks like I'm multiplying velocity by dt squared, and that shouldn't work to my knowledge. Isn't this a problem? If not, then why?

EDIT: Nevermind, I'm multiplying position by acceleration * dt², which makes sense since that is exactly how physics works.
ChronalDragon
Andrew Chronister
177 posts
2 projects

Developer, administrator, and style wrangler

#11937 Help with framerate independent updates/movement
1 month, 1 week ago

The answer is simple math. You can check whether it's correct by looking at the units:

Say your distances are in pixels (just to keep it video game).

A position or distance between two positions is in pixels: pix

Velocity is a change in position over a period of time: pix/sec

Acceleration is how fast the velocity is changing over time: pix/sec/sec or pix/sec²

The units of dt are, of course, in seconds. So if you multiply an acceleration by dt you get pix/sec² * sec = pix/sec. If you multiply a velocity by dt you get pix/sec * sec = pix.

This is easier to understand if you think about velocity and accelerating in terms of a calculus-ey understanding of changes in position:

velocity = dx/dt
acceleration = dv/dt = d²x/dt²

That is, velocity is the rate at which position changes over time, and acceleration is the rate at which velocity changes over time.

Note that the dt you have here is not actually a calculus "dt", which would be infinitesimal. So you may encounter problems if you try to do more complicated things with it, like a drag force that incorporates velocity:

F = C * v (where C is some coefficient of drag)

which you might write in a game as:

1
particle->acceleration += drag_coef * particle->velocity


As it turns out, the number of times that the velocity is added to the acceleration per second does actually matter, as I found out when I removed the sleep() from my game's update loop and the player could no longer jump high enough.
nyeecola
Italo
9 posts
#11938 Help with framerate independent updates/movement
1 month, 1 week ago

Yeah, I got it. Thanks for the explanation though.

Also, I'm actually interested in how you fixed that drag problem you proposed.
ChronalDragon
Andrew Chronister
177 posts
2 projects

Developer, administrator, and style wrangler

#11939 Help with framerate independent updates/movement
1 month, 1 week ago

Legitimately the only good answer I've found so far is -- "don't run physics with a variable timestep"

Apparently the industry standard way to fix this problem is to just run the physics at some fixed rate even if the game is rendering faster or slower, which kinda necessitates putting it on another thread.

If I can figure out the math to actually do the right thing, I'll post my solution
ratchetfreak
267 posts
#11941 Help with framerate independent updates/movement
1 month, 1 week ago

Another thing to keep in mind is that if your dt becomes small enough then then the per-frame updates will accumulate rounding errors. Though that'll start happening when adding numbers are 8 orders of magnitude apart.

The proper fix for when the coefficient changes over the time step is to work out the integral:

r(t+dt) = r(t) + \integral_t^{t+dt} C(x)dx

where r(t) is the resulting value from the previous timestep, r(t+dt) is the resulting value from the current time step. \integral_t^{t+dt} is the integral symbol with t at the bottom and t+dt at the top denoting the integral from t to t+dt. C(x) is the coefficient at time x.

For a constant coefficient this simplifies to r(t+dt) = r(t) + C/2*dt. when it's not constant this can quickly devolve into an unsolvable equation especially when the coefficient depends on the result in some way (like with a spring)