Search Unity

  1. The 2022.1 beta is now available for testing. To find out what's new, have a look at our 2022.1 beta blog post.
    Dismiss Notice

Adjusting Time.fixedDeltaTime by Time.timeScale

Discussion in 'Physics' started by PeachyPixels, Apr 16, 2020.

  1. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    342
    Hi Everyone,

    At various points in my game, the speed at which it is running can increase or decrease (using Time.timeScale). I've seen the example (below) that states Time.fixedDeltaTime should ideally be adjusted in step...

    https://docs.unity3d.com/ScriptReference/Time-timeScale.html

    So let's say the default values are...

    Time.timeScale = 1f
    Time.fixedDeltaTime = 0.02f

    Using the above example (and a 50% speed increase) the new values would be...

    Time.timeScale = 1.5f
    Time.fixedDeltaTime = 0.03f

    But I'm trying to understand why. Surely the frame rate does not change when Time.timeScale is changed, so why the need to alter the rate at which physics are updated? Even then, surely the rate should be increased? (so more updates)

    Or am I completely missing the point here? (very possible!)

    I've read a number of articles online on this subject, but still can't get my head around the need to decrease the rate. Any help would be much appreciated.
     
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,087
    I see no sense at all in that statement (adjusting Time.fixedDeltaTime when changing Time.timeScale). My guess is that part to be the result of some misunderstanding between the person writing the doc and the person providing the information.

    Time.timeScale defines the rate the game time (Time.time) advances with respect to real time. I use Time.timeScale extensively to provide pause, slow motion, fast-paced tests, etc but I never changed Time.fixedDeltaTime based on that. Indeed, doing so would provide unwanted results.

    Time.fixedDeltaTime defines the rate of the physics calculations. The default is 0.02 = 50 Hz. When you modify Time.timeScale that rate effectively varies based on the scale. For example, setting Time.timeScale = 1.5 means that everything will run 1.5 times faster. This includes both game time and physics, which in this case will run effectively at 75Hz to match the scaled time.

    Therefore the rule is:
    • Modify Time.timeScale to provide time scaling effects. Examples: accelerated time when a ship travels from a planet to another. Or slow motion for the replay of a car game. Leave it at 1 for real time.
    • Modify Time.fixedDeltaTime to configure a different rate for the physics calculations only. When this value changes the physics calculations will be different and will provide a different result. Leave it untouched when modifying Time.timeScale.
    EDIT: The documentation for Time.timeScale is clearly wrong about Time.fixedDeltaTime. Indeed, the documentation for fixedDeltaTime is correct when clarifying this aspect:

    https://docs.unity3d.com/ScriptReference/Time-fixedDeltaTime.html
    Note that the fixedDeltaTime interval is with respect to the in-game time affected by timeScale.

    EDIT 2: Indeed, even the code example of Time.timeScale is wrong. It aims to keep the fixed delta time at a constant rate in real time, but that would actually require dividing by timeScale, not multiplying. The example applies a timeScale of 0.7 and then multiplies fixedDeltaTime by 0.7. This results in the fixed delta time being scaled twice in real time.
     
    Last edited: Feb 1, 2021
  3. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    342
    Thanks Edy. That was exactly my understanding (and how I'm using it) but is also why I'm confused. You could argue for dividing by timeScale but even that doesn't seen necessary, given that fundamentally frame rate will not alter.

    Maybe someone from Unity can add to this or confirm that the documentation is indeed wrong.

    Thanks again for the clear reply, it's much appreciated.
     
    Last edited: Apr 17, 2020
  4. alexanderperrin

    alexanderperrin

    Joined:
    Dec 15, 2016
    Posts:
    19
    Hey there,

    Just wanted to chime in here to say that in implementing a 'bullet-time' effect for a 2D physics game of ours, I've found the documentation on scaling Time.fixedDeltaTime by Time.timeScale to be correct.

    We drop the timescale down to about 0.05 during certain moments. If fixedDeltaTime remains untouched (0.02 or 50hz), the game produces a visual 'stepping' effect where, because of the reduced timescale, you can perceive the individual 2D physics steps. To the user, the simulation appears to run at 2.5hz, not 50. If on the other hand, we keep the fixedDeltaTime proportionate to timeScale (eg. Time.fixedDeltaTime * Time.timeScale), the simulation remains perceivably smooth, or a constant realtime 50hz.

    Edit: I should note that multiplying fixedDeltaTime by timeScale has its benefits (ie. to reduce the stepping), it's not strictly required. The simulation will keep running fine in either case.
     
  5. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,087
    Hey, thanks for kicking in. I've reviewed my reply and the manual again and indeed I was wrong about the sample code, it does what its meant to do. I've removed that part from the reply.

    Although scaling fixedDeltaTime does as you say, I do think doing so is a very bad practice and shouldn't be mentioned in the manual as "recommended". The reason is that modifying fixedDeltaTime effectively modifies the physics behavior and any game logic based on fixed-timesteps.

    In your case, it's not exaggerated to asume that your game has two different physics behaviors, one in normal time and other in bullet time. Collisions among different objects will behave differently depending on the mode. This is a typical source of glitches that may be exploited by the users to, for example, clipping through walls, making some situation behave in a convenient way, etc.

    If the problem is the visual stepping then the correct solution is enabling Rigidbody2D.interpolation. This feature is specifically designed to solve it:
    Using interpolation and leaving fixedDeltaTime untouched ensures your game physics behaves exactly the same no matter the actual time scale, and will show perfectly smooth motion at the same time.

    Note that without interpolation your game may still produce slight visual stepping at normal time scale. Physics updates at 50Hz, while the screen refresh rate is typically 60Hz and above. This necessarily means that there will be a small "step" at least 10 times every second. Interpolation solves that as well.
     
    alexanderperrin likes this.
  6. alexanderperrin

    alexanderperrin

    Joined:
    Dec 15, 2016
    Posts:
    19
    Ahh, this is super interesting! I was going to say, for the most part, our scaling of fixedDeltaTime has been perfect, but recently we've been encountering some infrequent but seriously strange issues (eg. objects suddenly gaining an intense amount of velocity for no apparent reason) when bullet time modes take place. Sounds like it might be caused by what you've mentioned. Do you have any resource links or understanding of why behaviours such as collisions have different results when fixedDeltaTime is altered?

    Great advice on using interpolation instead. I had forgotten about this as an option!
     
  7. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,087
    I don't really have any resource on this, but an understanding on how physics engines work. If all, I'm used to watch speedruns where popular games are played really fast from their begin to their end. Speedrunners make extensive use of this kind of glitches to skip large portions of the games. Here's an example of exploiting a similar physics-related glitch, but you can find a lot of them in mostly any speedrun video.

    In our case, simplifying things a lot, we can think of the physics engine doing two things every frame:
    1. Update motion: p1 = p0 + v * dt
    2. Resolve collisions using dt
    Collisions must be resolved in a single frame so after the next frame the objects don't interpenetrate. This involves computing a speed (momentum) that ensures that once applied the objects aren't overlapping each other.

    Example: In step 2 the engine detects an object penetrating 10 cm into other. It then computes the speed that moves the object 10 cm in a single frame, that is, v = 10 / dt. Next frame the engine computes p1 = p0 + v * dt = p0 + 10cm, so the object moves exactly 10 cm and the object no longer overlaps the other. Good.

    In your game, if the above collision happens during bullet time (dt = 0.02 * 0.05 = 0.001), then the depenetration speed is computed as v = 10 / 0.001 = 10000 cm/s. In the next frame the step 1 computes the new position, which is p1 = p0 + 10000 * 0.001 = p0 + 10cm. Good.

    But what happens if dt changes between frames? The step 2 computes the speed based on the current dt, but the step 1 applies that speed using a different dt. Following our example, the step 1 computes the new positions as p1 = p0 + 10000 * 0.02 = p0 + 200cm. This is 20 times the speed required to depenetrate the objects in the new dt.

    On the other hand, if you simply use Time.timeScale and rigidbody interpolation, dt never changes and the collisions are properly resolved no matter the time scale.
     
    Last edited: Feb 3, 2021
  8. alexanderperrin

    alexanderperrin

    Joined:
    Dec 15, 2016
    Posts:
    19
    That makes complete sense. Amazing! Thanks for the incredibly detailed explanation.
     
    Edy likes this.
  9. unity_76387

    unity_76387

    Joined:
    Jul 14, 2020
    Posts:
    1
    The fixedDeltaTime is controlled by time in unity. Update calls by frame rate. Fixed update calls when an amount of time passes in unity time.
     
unityunity