If you've ever watched a tutorial about adding movement to your game, chances are you've come across delta time.
The first thing we're taught is that it's necessary if we want to keep an object's speed consistent even when framerate varies.
"Don't do this," they say, "and players with higher FPS will move faster than those with lower."
It's true. But why?
You have a car starting at position 0.
You want to move it at 10 units/second by changing its position.
For simplicity's sake, let's forgo vectors and do things in 1 dimension: the number line.
The first thing we must understand is that the game code executed every frame... is executed every frame.
So, you cannot just write
car.position += 10 in
Update and expect it to work. That's going to add 10 units every frame. In other words, the car's speed isn't 10 units/second; it's 10 units/frame. If your game runs at a consistent 50 frames/second, that's
10 * 50 = 500 units/second!
If it runs at 60, it's 600. 40? 400. You can see why framerate changes speed.
This is where delta time comes in. In Unity, you may know this as
Delta time is the time it took to render the frame. Another way to put it: delta time is the time period between last frame and the current.
(Delta means "difference".)
If the game runs at a consistent 50 frames/second, delta time will always be 1/50, or 0.02, seconds per frame.
How can we use this? It's the same thing we did in our high-school physics classes.
When we write
car.position += 10 * Time.deltaTime, we write 10 units * 0.02 seconds/frame, or 0.2 units * seconds / frame. If the game runs at 50 frames per second, why, that's the same as saying the following:
Frames and seconds cancel out, and, 50 frames later, we're left with
0.2 * 50 = 10 units!
Of course, games rarely, if ever, run at a dead-steady FPS. But as framerate changes, so does delta time. A higher FPS means lower delta time and vice-versa. Measured over a certain period of time — say, 1 second — delta time will always be the reciprocal of the number of frames drawn in that time. After all, it's not that delta time is measured by framerate; framerate is measured based on delta time!
Delta time therefore lets us not only keep an object's speed consistent despite varying framerates, but also to give it precisely the speed we desire, instead of blindly flailing for the right number.
Once you understand this, you realize how much more you can do with it. For example, I recently worked on a mechanic where you drag a ball around with your mouse and, when you let go, the ball goes flying.
The problem is that the ball will not, on its own, go flying. All I'd done was disable the physics and make it follow the mouse cursor when clicked. The moment the player let go, the ball would just... stop. And then physics would kick in again and gravity would take it down.
As such, I had to measure its velocity at that last moment and assign it manually. How? First, we must understand that there's no such thing as speed or velocity at some particular instant. By definition, an object's velocity describes change; change in position. It's measured by the time it took to cover a certain distance (v = S/t), and if there's no change, there's no velocity.
If you measure over, say, 1 hour, sure, you get a velocity, but it hardly describes the object at a particular instant. No, we want the time and the distance to be as short as possible.
The shortest we can get in games is how much distance the object covered over 1 frame. So, I recorded just that. An example: the ball covered 0.2 units. So, its speed is 0.2 units/frame. Now, how do we convert it to units/second, which is what the physics engine runs on?
If we again assume a steady framerate of 50, delta time is 0.02 seconds/frame. We divide the 0.2 units/frame with 0.02 seconds/frame, giving us the following:
Ta-da! 10 units/second. Now we write
rigidbody.velocity = velocityWeJustCalculated — and we're done!
Why'd we get a result in units in the first problem and in units/second in the 2nd?
Because, in the first problem, we were changing the position; every frame, to be exact. We needed the correct distance to advance with every frame, such that it added up to 10 units in 1 second.
In the 2nd, we were assigning velocity; once, when the player lets go. So, we needed not just distance — units — but speed.