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