How to obtain framerate-independent constant acceleration in a video game?

I struggled with making my games framerate-independent for quite some time. I understood that I had to use Time.deltatime when computing movement, and it worked fine with a constant velocity. However, whenever I added some acceleration, in a racing game for instance, the objects’ velocity became framerate-dependent: the faster the framerate, the faster the cars would go. 

My goal with this article is to show you how to make your game framerate-independent when applying constant acceleration. For the more nerdy ones, I will also go over why it works. Please note that what I will show you only works for constant acceleration and not for other kinds of acceleration, for instance, exponential, logarithmic, etc. 

 

The wrong way to apply constant acceleration

First, let me go over what I used to do and why it doesn’t work.

For each frame I computed the displacement Δx, the distance traveled, the velocity, the acceleration, and Δt, the elapsed time between frames.

Δx = v * Δt

v = v + a*Δt

So, in pseudo code, repeating each frame, it would go like this:

float v = 0;

float a = 5;

// Calculating new velocity

v = v + a*Δt

// Calculating displacement

Δx = v * Δt

Now let’s compare the results when plugging different numbers for Δt. Let’s say the game runs for 2/60 seconds (roughly 0.0333 seconds), which amounts to 2 frames at 60 fps (0.01667 *2) and 1 frame at 30fps (0.03333).

60 fps

So this bit of code would run twice, once per frame.

float v = 0;

float a = 5;

Frame 1 (ends at 0.01667 seconds)

// Calculating new velocity

//v = v + a*Δt

v = v + 5 * 1/60

// At that moment, v = 5/60 (roughly 0.083333)

// Calculating displacement

Δx = 5/60 *1/60

// For that frame, displacement = 5/3600 (roughly 0.001388)

Frame 2 (ends at 0.0333 seconds)

// Calculating new velocity

//v = v + a*Δt

v = 5/60+ 5 * 1/60

// At that moment, v = 10/60 (roughly 0.166666)

// Calculating displacement

Δx = 10/60 *1/60

// For that frame, displacement = 10/3600 (roughly 0.00277777777)

So during the first 2/60 seconds of the game (0.03333s), the total displacement, in other words, the total distance traveled by the object during the first 2/60 seconds of the game is = (5/60 *1/60) + (10/60 *1/60) = 15/3600 (roughly 0.004166)

30 fps

Now, let’s run the exact same code but at 30 fps, so only once, since 1/30 frame/seconds = 0.0333, and that’s the total time we want the code to run. 

Frame 1 (ends at 0.0333 seconds)

// Calculating new velocity

//v = v + a*Δt

v = v + 5 * 1/30

// At that moment, v = 5/30 ( roughly 0.1666)

// Calculating displacement

Δx = 5/30 *1/30

// For that frame, displacement, and actually total displacement, since there is only one frame is 20/3600 (roughly 0.00555555555)

We are using Time.deltaTime, so why do we get different results? Why doesn’t the object travel more distance at 30 fps than at 60 fps, while velocity and acceleration are identical for both framerates? I thought that multiplying both velocity and displacement by the elapsed time between frames was the correct way to have framerate-independent movement, as Time.deltatime would fill the gap between frames, based on how long they lasted. I was wrong.

Velocities are the same, at the same points in time:

velocity 60fps.PNG
velocity 30 fps.PNG

Yet total displacements at each frame are not the same:

total displacement 60fps.PNG
total displacement 30fps.PNG

Through deduction, we can see that there is only one parameter that varies: the elapsed time between frames: Δt.

To get the displacement, we multiply the velocity by the elapsed time. The elapsed time, and the number of updates varies from 30 to 60 fps. So there is no wonder why we get different numbers when considering the total displacement.

60 fps

Frame 1

Δx = 5/60 *1/60 = 5/3600

Frame 2

Δx = 10/60 *1/60 = 10/3600

Total displacement = 15/3600

30 fps

Frame 1

Δx = 5/30 *1/30

Total displacement = 20/3600

The right way to apply constant acceleration

While doing research, I came across this post:

https://answers.unity.com/questions/1175418/yet-another-timedeltatime-question.html, and after doing a little research on my own, things were much clearer. 

In order to figure out how much an object should move each frame, we have to leverage this kinematic equation: 

Δx = displacement, i.e. how far the object moves

v = final velocity, i.e. in our case the object’s current velocity this frame

vo = the original velocity, i.e. in our case the object’s velocity during the previous frame

Δt = the time elapsed between the beginning and the end of the movement, i.e. in our case the time elapsed between the last and current frame. 

v, final velocity is calculated as follow: v= acceleration * Δt

Equation 1.PNG

The equation can also be rewritten like this.

In my opinion, the latter form, while less compact, is more readable. Especially when you are still wrapping your head around how constant acceleration is calculated. 

equation 2.PNG

I think it’s better, when you can, to understand the math involved in your code. So I refreshed my knowledge with this course from Khan Academy: https://www.khanacademy.org/science/physics/one-dimensional-motion.

So now let’s apply this equation to our game. Let’s rework the pseudo code we made above.

60 fps

float vf = 0;

float vo = 0;

float a = 5;

Frame 1

// Calculating new final velocity

//vf = vo + a*Δt

vf = 0 + 5 * 1/60;

// At that moment, vf = 5/60 (roughly 0.083333)

// Calculating displacement

// Δx = vo*Δt + (vf-vo)/2 *Δt

Δx1 = 0 * 1/60 +(5/60 - 0)/2 * 1/60 (roughly 0.0006944)

// For the next frame, the original velocity will be this frame’s final velocity

vo = vf

Frame 2

// Calculating new final velocity

//vf = v0 + a*Δt

vf = 5/60 + 5 * 1/60;

// At that moment, vf = 10/60 (roughly 0.16666)

// Calculating displacement

Δx2 = 5/60 * 1/60 + (10/60 - 5/60)/2 * 1/60 (roughly 0.00208333333)

Total displacement = Δx1 +Δx2 = 0.00277777777

30fps

float vf = 0;

float vo = 0;

float a = 5;

Frame 1

// Calculating new final velocity

//vf = vo + a*Δt

vf = 0 + 5 * 1/30;

// At that moment, vf = 10/60 (roughly 0.16666)

// Calculating displacement

Δx = 0 * 1/30 + (10/60 - 0)/2 * 1/30 =0.00277777777

Total displacement Δx1 =0.00277777777

So what’s great here, is that for both framerates, the object traveled the same distance (total displacement) over the same period of time (Δt), thus making our game framerate-independent.

As before, same velocity at each point in time:

vel 60.PNG
vel 30.PNG

But this time the final displacement, or distance traveled, is the same:

displacement 60.PNG
displacement 30.PNG

Why does it work?

Here, I am not going over the calculations again, just explain to the best of my ability, why it makes sense.

Why does the constant acceleration kinematic equation actually make displacement framerate-independent?

If you plot velocity over time, then displacement is the area under the curve, or velocity * Δt.

First let’s consider constant velocity, not constant acceleration, as it is easier to grasp.

For instance if you go 5 m/s² for 5s, you’ll go 25 meters.

Capture 1.PNG

In our case we use constant acceleration, so the graph looks a bit different, but it’s still the same idea. So let’s break it down. Remember the equation is:


Capture 2.PNG

When we apply this equation to a video game, in other words, a frame-based system, at the beginning of each frame vo is the previous frame’s final velocity. 

Because the acceleration is constant, we get this triangle shape. The line is straight because the acceleration is constant, hence it is linear.

60 fps

Frame 1

Δx = I

vo * Δt + (vf-vo)/2 * Δt

Frame 2

Δx = II + III

II = vo * Δt

III = (vf-vo)/2 * Δt

 
Capture 4.PNG
 
 
Capture 3.PNG

30 fps

Frame 1

Δx = I

vo * Δt + (vf-vo)/2 * Δt

For both fps, and any fps for that matter, if you plug in their respective vf, vo and Δt, the area under the curve, the total displacement, is the same. 

Applying constant acceleration in Unity

I made a Unity project to show how to apply constant acceleration in a video game. You can download it here: https://github.com/willy1989/constant-acceleration

It’s just a cube with a script that controls its movement attached to it. 

 
 
 
 
 
Unity 2.PNG

So can see for yourself that the cube moves at the same speed, at 60, 30, 120, 10 or any fps, I also made a script that forces the game to run at a certain fps:

unity 1.PNG

Here is the function that calculates displacement and moves the object each time Update() is called, i.e. each frame.

 
Unity 3.PNG

Thank you very much for reading my article. 

Feel free to share your feedback. I’d love other developers to kind of do a peer review, and let me know what they think of my method. 

You can get a hold of me at @Willy_game_dev on Twitter, or you can send an email to willygamedev@gmail.com or willymercier@outlook.fr.