Unity  

Time.deltaTime Explained in Unity

Delta time

When developing games in Unity, one of the fundamental challenges is making movement, animations, and physics behave consistently across devices with varying frame rates. What runs smoothly at 60 FPS on a high-end PC may stutter or lag on a slower machine or one that temporarily exceeds 120 FPS. Unity’s Time.deltaTime is the go-to solution for this: it provides the precise duration (in seconds) of the last rendered frame, enabling you to scale any per-frame operation so it behaves the same regardless of frame rate.

Why does Frame-Rate Independence matter?

  • Consistency Across Devices: Without frame-rate compensation, movement speeds and animations are tied directly to the rate at which frames are rendered. At 30 FPS, a character moving 1 unit per frame travels 30 units/sec; at 60 FPS, that same code yields 60 units/sec twice as fast!
  • Gameplay Fairness: In multiplayer or competitive games, a faster machine shouldn’t gain an “unfair” speed boost or smoother input response merely by rendering more frames.
  • Predictable Physics & Animations: Even in single-player titles, you want movement, timers, and effects to feel stable whether the game dips in performance or spikes above 60 FPS.

What is Time.deltaTime?

Time.deltaTime is a float representing the time, in seconds, since the last frame was rendered. For example, if your game is running at a constant 60 FPS, Time.deltaTime will be approximately 0.01667 seconds (1/60). If it dips to 30 FPS, deltaTime jumps to ≈ 0.03333 seconds.

Key point: Always multiply any per-frame change (movement, rotation, scaling, timers) by Time.deltaTime to convert it into a per-second change.

void Update()
{
    float speed = 5f;                    // Units per second
    float moveAmount = speed * Time.deltaTime;
    transform.Translate(moveAmount, 0, 0);
}

Without that multiplication, Translate(5, 0, 0) would move 5 units every frame rather than per second.

Update() vs. FixedUpdate()

1. Update()

  • Called once per frame.
  • Use for input and frame-dependent logic.
  • Multiply by Time.deltaTime.

2. FixedUpdate()

  • Called at a fixed interval (default 0.02 s → 50 Hz).
  • Used for physics (Rigidbody, Colliders).
  • Instead of Time.deltaTime, Unity provides Time.fixedDeltaTime (the fixed timestep).
    void FixedUpdate()
    {
        float force = 10f;
        float impulse = force * Time.fixedDeltaTime;
        rb.AddForce(Vector3.forward * impulse, ForceMode.Impulse);
    }
  • Mixing Time.deltaTime in FixedUpdate can introduce inconsistencies since physics steps run on their own cadence.

Common Use-Cases

Smooth Movement

void Update()
{
    Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    float moveSpeed = 3f;
    controller.Move(direction * moveSpeed * Time.deltaTime);
}

Rotations & Smooth Look

void Update()
{
    float yaw   = Input.GetAxis("Mouse X") * 200f * Time.deltaTime;
    float pitch = -Input.GetAxis("Mouse Y") * 200f * Time.deltaTime;
    transform.Rotate(pitch, yaw, 0);
}

Timers & Cooldowns

private float cooldown = 5f;
private float timer;

void Update()
{
    timer += Time.deltaTime;
    if (timer >= cooldown)
    {
        FireProjectile();
        timer = 0f;
    }
}

Unscaled & Smoothed Variants

  • Time.unscaledDeltaTime: Ignores any Time.timeScale adjustments (e.g., during slow-motion effects).
  • Time.smoothDeltaTime: A smoothed average of recent deltaTime values, useful if your frame rate is highly variable and you need less jitter.
    float realTimeSinceStartup = Time.unscaledDeltaTime + Time.unscaledDeltaTime;  
    float smoothFrameDelta = Time.smoothDeltaTime;

Pitfalls & Gotchas

  • Neglecting to Multiply:Forgetting * Time.deltaTime is a frequent bug. Movements become frame-dependent.
  • Using deltaTime in FixedUpdate(): This can lead to physics forces being incorrectly scaled, as physics runs at its own fixed rate.
  • Extreme Frame-Rate Swings: At very low frame rates (e.g., < 10 FPS), a large deltaTime can cause “tunneling” (objects passing through colliders) or huge jumps. Clamping your per-frame movement or time step can help.
    float dt = Mathf.Min(Time.deltaTime, 0.05f); // cap at 50 ms
    transform.Translate(speed * dt, 0, 0);

Time Scale Side-Effects: If you pause the game by setting Time.timeScale = 0, deltaTime becomes 0. Any movement or timers in Update() will freeze. Use unscaledDeltaTime for any UI animations or effects you want to continue despite pause.

Best Practices

  • Always think in “units per second”: Define speeds, rotations, or rates in per-second terms, then multiply by deltaTime.
  • Separate input → logic → physics: Read inputs in Update(), apply physics in FixedUpdate(), each with the correct delta.
  • Clap large deltas: Safeguard against spiraling updates when frame rates plunge.
  • Use unscaled time where appropriate: UI elements and countdowns, which you still want to display during slow motion or pause.
  • Profile on target hardware: Test on slow and fast devices. Observe deltaTime fluctuations in the Profiler to catch unexpected spikes.

Conclusion

Time.deltaTime is the cornerstone of frame-rate-independent game logic in Unity. By converting per-frame changes into per-second rates, you ensure consistent behavior across unsteady frame rates and varied hardware. Mastering deltaTime, along with its cousins fixedDeltaTime, unscaledDeltaTime, and smoothDeltaTime, is essential for smooth movement, fair gameplay, and predictable physics in any Unity project.