FixedUpdate interval broken for the frame after a TimeScale change

In the first FixedUpdate after changing Time.timeScale (and the respective usual Time.fixedDeltaTime), Time.fixedUnscaledDeltaTime is incorrect.
This causes FixedUpdate to be called more times than it should the frame after a timeScale change. This breaks logic that depends on FixedUpdate being properly “fixed” (such as in fighting games or netcode)

Further, the behavior is inconsistent and is reliably “worse” (i.e. the number of erroneous FixedUpdates run greater) when VSYNC is enabled (but still exists with it off)

For reproduction, simply use this script on a gameObject in a new unity project:

public class TimeTests : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(ReduceTimeScale());
    }

    private IEnumerator ReduceTimeScale()
    {
        yield return new WaitForSecondsRealtime(2);
        Debug.Log("Update time scale");
        Time.timeScale /= 10;
        Time.fixedDeltaTime /= 10;
    }

    private void Update()
    {
        Thread.Sleep(33);
        Debug.Log($"[UPDATE] Frame {Time.frameCount}, Unscaled delta time: {Time.unscaledDeltaTime}, Delta time: {Time.deltaTime}, Unscaled time: {Time.unscaledTime}, Time: {Time.time}, TimeScale: {Time.timeScale}");
    }

    private void FixedUpdate()
    {
        Debug.Log($"[FIXED_UPDATE] Frame {Time.frameCount}, Fixed unscaled delta time: {Time.fixedUnscaledDeltaTime}, Fixed delta time: {Time.fixedDeltaTime}, Fixed unscaled time: {Time.fixedUnscaledTime}, Fixed time: {Time.fixedTime}, TimeScale: {Time.timeScale}");
    }
}

Which has example output:

[UPDATE] Frame 22, Unscaled delta time: 0,0421071, Delta time: 0,0421071, Unscaled time: 6,102326, Time: 1,17877, TimeScale: 1
[FIXED_UPDATE] Frame 23, Fixed unscaled delta time: 0,02, Fixed delta time: 0,02, Fixed unscaled time: 6,103556, Fixed time: 1,18, TimeScale: 1
[FIXED_UPDATE] Frame 23, Fixed unscaled delta time: 0,02, Fixed delta time: 0,02, Fixed unscaled time: 6,123556, Fixed time: 1,2, TimeScale: 1
[UPDATE] Frame 23, Unscaled delta time: 0,0374097, Delta time: 0,0374097, Unscaled time: 6,139736, Time: 1,21618, TimeScale: 1
Update time scale
[FIXED_UPDATE] Frame 24, Fixed unscaled delta time: -0,1256213, Fixed delta time: 0,002, Fixed unscaled time: 5,997935, Fixed time: 1,202, TimeScale: 0,1
[FIXED_UPDATE] Frame 24, Fixed unscaled delta time: 0,02, Fixed delta time: 0,002, Fixed unscaled time: 6,017935, Fixed time: 1,204, TimeScale: 0,1
[FIXED_UPDATE] Frame 24, Fixed unscaled delta time: 0,02, Fixed delta time: 0,002, Fixed unscaled time: 6,037935, Fixed time: 1,206, TimeScale: 0,1
[FIXED_UPDATE] Frame 24, Fixed unscaled delta time: 0,02, Fixed delta time: 0,002, Fixed unscaled time: 6,057935, Fixed time: 1,208, TimeScale: 0,1
[FIXED_UPDATE] Frame 24, Fixed unscaled delta time: 0,02, Fixed delta time: 0,002, Fixed unscaled time: 6,077935, Fixed time: 1,21, TimeScale: 0,1
[FIXED_UPDATE] Frame 24, Fixed unscaled delta time: 0,02, Fixed delta time: 0,002, Fixed unscaled time: 6,097935, Fixed time: 1,212, TimeScale: 0,1
[FIXED_UPDATE] Frame 24, Fixed unscaled delta time: 0,02, Fixed delta time: 0,002, Fixed unscaled time: 6,117935, Fixed time: 1,214, TimeScale: 0,1
[FIXED_UPDATE] Frame 24, Fixed unscaled delta time: 0,02, Fixed delta time: 0,002, Fixed unscaled time: 6,137935, Fixed time: 1,216, TimeScale: 0,1
[FIXED_UPDATE] Frame 24, Fixed unscaled delta time: 0,02, Fixed delta time: 0,002, Fixed unscaled time: 6,157935, Fixed time: 1,218, TimeScale: 0,1
[UPDATE] Frame 24, Unscaled delta time: 0,0375348, Delta time: 0,00375348, Unscaled time: 6,177271, Time: 1,219934, TimeScale: 0,1

Showing the initial negative FixedUnscaledDeltaTime, followed by a number of erroneous FixedUpdates because unity is trying to “catch up” with that negative value (?)

NOTE: this occurs regardless of where Time.timeScale and Time.fixedDeltaTime are updated; Update, LateUpdate, FixedUpdate all yield the same behavior

Do NOT modify Time.fixedDeltaTime when changing Time.timeScale. That’s what breaks the logic that depends on FixedUpdate.

Contrarily to what Unity manual says, you shouldn’t change Time.fixedDeltaTime when modifying Time.timeScale. That leads to inconsistent glitches that are hard to reproduce and trace. Here’s an in-depth discussion with practical examples:

1 Like

Interesting insight, however, if physics calculations should indeed be adjusted to be consistent with realtime, how should this be handled without the issues described here?

I think the issue described here is still indeed a bug is it not?

Think about a timeslow in a fighting game – if the physics timestep is not modified the timeslow will look pretty bad, so not updating Time.fixedDeltaTime per the documentation isn’t an option.

Is there a way you theorize this is possible with perhaps in a different way?

It’s not a bug, it’s how physics simulations work. Consistent physics require fixed time step. Modifying the timestep dynamically produces inconsistencies and glitches.

That’s what interpolation is for. Rigidbodies with interpolation enabled show perfectly smooth motion regardless the value of Time.timeScale. Other elements may require implementing interpolation explicitly, but it’s straightforward: the visual pose (Update) is an interpolation between the two latest FixedUpdate poses.

Thanks a lot for your replies here. Makes total sense. Perhaps the docs should be updated on this topic. I’ll experiment and update this thread with my findings.

It makes sense this could cause inconsistencies if it’s applying the updated timeStep interval “now” (explaining the race condition and why it wants to “catch up”), but to push back slightly on the idea that this not a bug – this issue wouldn’t exist if unity waited to update this after the current timeStep or had a way to “safely” update the value

My theory is it occurs because the current time isn’t marked as “processed” which could be an easy “fix” if it was swapped somewhere internally but I’m just wildly guessing

@Edy important update: this issue seems to persist without updating fixedDeltaTime at all – especially when vsync is enabled; in the fixedUpdate immediately after the timescale update,fixedUnscaledDeltaTime is incorrect and sometimes numerous fixedUpdates are called to “catch up” incorrectly

Definitely seems like a bug in which unity cannot be relied on for FixedUpdate actually being fixed if changing Time.timeScale

Then the issue is related with fixedUnscaledDeltaTime only: how is computed internally, when it’s updated, and if it can actually be compared with the fixed time when timescale is applied. Perhaps it’s just not intended to be used that way.

As per the logs in the original post, I can’t see anything wrong with FixedUpdate or Fixed Time. After changing the fixedDeltaTime, FixedUpdate is called with timestamps every 0.002 seconds instead of every 0.02 seconds, exactly as expected.

What I can confirm is that there are no issues with FixedUpdate/Physics and Time.timeScale when used with constant fixedDeltaTime. I make extensive use of Time.timeScale in very complex and demanding physics simulations with logic based in FixedUpdate. For example, these include recording and replaying the physical positions producing the same exact physical effects. If there were even a single FixedUpdate called incorrectly, or with unexpected timestamp, it would have been clearly noticed. But that never happened.

@Edy I appreciate the discussion but I assure you I have proof in the behavior of my game that FixedUpdate timing is not working in a proper “fixed” manner.

My updated logic that only updates timeScale still does not work as it should due to something about the behavior of Unity.

You can reproduce it quite easily:

  • do a time slow of perhaps 1/100
  • make this time slow last only one or two FixedUpdate frames
  • test a lot

You’ll see that the time slow is sometimes skipped alltogether, with Unity improperly managing the time of fixed updates such that they occur way too quickly temporarily

Additionally, if you turn on vsync in the game tab in the inspector, it occurs way more often. (the issue is uncommon but definitely still exists otherwise)

This is definitely a bug and breaks relying on fixedUpdate for multiplayer games or fighting games

If you have what you believe is a bug, and can reproduce it, submit a bug report.

I believe there’s some misunderstanding regarding how FixedUpdate works. There’s no guarantee of a 1:1 correspondence between the timing of the calls to FixedUpdate and real-world time. In Unity’s game loop, everything must be processed sequentially from the main thread, including Update, FixedUpdate, rendering, physics, and other subsystems. This means that multiple Update or FixedUpdate calls may occur in quick succession within a single game loop update. This is by design.

The example provided in this manual page illustrates what happens with FixedUpdate calls in Unity. Simplifying it a bit, game time advances on each Update cycle, and then FixedUpdate calls are invoked in rapid succession to catch up.

Code that runs within FixedUpdate remains consistent—it only “sees” fixed time advancing in fixed steps, which ensures steady physics and game logic updates. That’s the “real time” for the FixedUpdate code. When the Update section is reached, the current state of physics objects is rendered, with interpolation applied from the latest update (if enabled).

If you need code to run at specific intervals based on real-world time, you’ll need to create a separate thread and manage the timing yourself. This ensures that at the specified intervals, the CPU runs your code in a separate thread. However, most of the Unity API is only accessible from the main thread.

I can’t see anything here that indicates a bug in Unity. However, if you can provide a consistent way to reproduce the issue, feel free to submit a bug report. That said, I believe the most likely response would be “by design”.

1 Like