Skip to content

Replace Time's oversized-delta clamp with a fixed-timestep accumulator for physics #550

Description

@stormmuller

Problem

Time.update (src/common/time/Time.ts) clamps deltaTimeInMilliseconds to a max of 1000/15 (~66.7ms) to prevent a large delta after a frame hitch/stall from causing instability — most concretely, physics bodies tunneling/flinging apart when a huge single-step integration is applied from a stale state (see the Newton's Cradle fix in commit c70a2bf).

This clamp lives on the shared Time class, so every consumer (physics, timers, particles, anything reading deltaTimeInMilliseconds/deltaTimeInSeconds) inherits it, not just physics. The side effect: during a real hitch, simulated time falls behind wall-clock time and everything runs in slow motion until it "catches up" tick by tick, rather than the sim catching up in the same frame.

Idiomatic fix

Adopt a fixed-timestep accumulator (see Glenn Fiedler's "Fix Your Timestep!") scoped to physics/simulation systems: accumulate real elapsed time and run integration/collision resolution in one or more fixed-size substeps per frame until the accumulator drains, clamping the accumulator itself (not the raw delta) to bound worst-case substeps per frame. This preserves physics stability without the global slow-motion side effect on unrelated systems (timers, particles, etc.), and gives real catch-up behavior after a hitch instead of stretched-out simulated time.

Scope

  • Introduce a fixed-timestep loop (accumulator + substep count clamp) around physics integration/collision resolution, likely in the physics module's system(s) or a new stepping layer above them.
  • Revisit whether Time's oversized-delta clamp is still needed for other consumers once physics no longer depends on it, or whether it should stay as a coarser global safety net.
  • Architectural — decouples physics tick rate from render tick rate; worth a design pass before implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions