So, it was said (paraphrased as I get it) that Time.fixedDeltaTime returns the interval at which the FixedUpdate method should be called with respect to the timeScale.
Yes, it's the interval of game time between successive FixedUpdate
calls.
But the real interval could differ (for technical reasons) and that's why Time.deltaTime should be used instead to return a real time elapsed since the previous FixedUpdate call.
No.
You can imagine deltaTime
being implemented something like this:
public float deltaTime { get {
if (_isCurrentlyRunningFixedUpdates) {
return fixedDeltaTime;
} else {
return Mathf.Min(timeScale * _realtimeSecondsSinceLastFrame, maximumDeltaTime);
}
} }
Basically deltaTime
is a getter that returns "how much game simulation time should I treat as having passed, based on where in the update flow I am currently running?".
If you're in a fixed step (physics updates, FixedUpdate
, collision handling messages), it gives you exactly the same value as writing fixedDeltaTime
instead.
That's the point of a fixed time step: it's fixed - it does not change no matter what weirdness might be happening with regard to wall-clock-time.
If you're in a variable step (Update
, LateUpdate
), it gives you the amount of game simulation time that's run since the last rendered frame, which could be more or less depending on your framerate, transient load spikes, etc.
The convenience of this behaviour is that if you have a function that's called in multiple places, sometimes from FixedUpdate
or a collision handler and sometimes from Update
, it automatically adapts itself to give the right value for that context. Or if you refactor some code and move it from one update to another, you don't need to remember to update the time step you're using, as long as you've been consistent about always reading Time.deltaTime
.
It's important to remember that fixedDeltaTime
is a measure of game simulation time. It is not a measure of real time.
When running a fixed update loop, the game measures the total realtime / wall clock time elapsed since the last frame, scales it by your time scale, and then divides that by your fixedDeltaTime
to get an integer representing how many times it should tick the physics simulation this frame. Any fractional part is carried over as loose change to add to the calculation for next frame.
So on a short frame, you might not run the physics step or FixedUpdate
at all. On a longer frame, you might run the physics step and FixedUpdate
functions multiple times.
When we do tick multiple times in one frame, all those ticks are run in rapid succession back-to-back. We don't put delays in between them so that each is called one fixedDeltaTime
apart from the last with regard to the wall clock. Because again, fixedDeltaTime
measures game sim time, not wall clock time.
What matters is that "by the time we get to a frame \$x\$ seconds into the game, I expect \$\lfloor 50 \cdot x\rfloor\$ FixedUpdate
steps have run" (if using the default 0.02
value for fixedDeltaTime
and a timeScale
of 1.0
). So we don't get ahead the rendered frame, or fall behind it by a fixedDeltaTime
or more.
When exactly in wall clock time that code ran on the CPU doesn't matter - it's not directly observable by the player, all they can see is the resulting rendered frame that gets presented after we've done all the catching-up we need to do for this frame.
There is an exception in the case where your computer just can't keep up with running the number of physics steps / FixedUpdate
calls needed to keep pace: Unity provides a maximum allowable game time step. If your frame time runs so long that the game simulation it accounts for exceeds this limit, then Unity will stop running fixed steps and cap the simulation as far as it got this frame, resuming next frame. In this situation, game time slows down relative to real time until the computer is able to catch up. But each FixedUpdate
call still represents exactly the same amount of game time as before.
Unity does not adjust fixedDeltaTime based on Time.timeScale. The fixedDeltaTime interval is always relative to the in-game time which Time.timeScale affects.
Don't these two sentences contradict each other?
No. What this is saying is that changing the value you put into Time.timeScale
does not change the value you read from fixedDeltaTime
.
By setting fixedDeltaTime
to 0.02
, I am saying "I want physics to tick and FixedUpdate
to run exactly 50 times per second of game time". And Unity honours that.
If I speed up game time so it's running 2 seconds of simulation for every 1 second of real time, then Unity will run 100 physics steps for every wall clock second (still 50 per game second)
If I slow down my game time so it's running at half a second of simulation for every 1 second of real time, then Unity will run 25 physics steps for every wall clock second (still 50 per game second)
Time.timeScale
changes the relationship between game time and real time. fixedDeltaTime
is measured in game time, so this scaling does not affect it.