AnyLearn
All lessons
Programmingintermediate

Unity: physics and the fixed timestep

Why Unity runs physics on its own 50Hz clock instead of the frame rate, and what follows from that. Covers rigidbodies and colliders, moving things correctly with forces rather than the Transform, interpolation for smooth motion, tunneling and continuous collision detection, and where physics cost actually comes from.

Updated · AI-authored, review-gated · how lessons are made

Not signed in: your progress and quiz score won't be saved.
Progress1 / 9

Two clocks, and why

Rendering runs as fast as the machine allows. Physics does not. Unity steps the physics simulation on a fixed timestep, 0.02 seconds by default, which is 50 steps per second, set under Edit > Project Settings > Time > Fixed Timestep.

The reason is stability. A physics solver integrates forces over a time slice, and its accuracy depends on that slice being small and predictable. Feed it a variable frame time and identical situations resolve differently on different hardware: a stack of crates that settles on a desktop explodes on a phone that hitched for 200 milliseconds.

So Unity decouples them. However long the frame took, physics advances in uniform 0.02s bites. If a frame took 0.05s, the engine runs the step twice and carries the remainder. If a frame took 0.008s, physics may not step at all.

Everything else in this lesson follows from that one decision.

Full lesson text

All 9 steps on one page, for reading, reference, and search.

Show

1. Two clocks, and why

Rendering runs as fast as the machine allows. Physics does not. Unity steps the physics simulation on a fixed timestep, 0.02 seconds by default, which is 50 steps per second, set under Edit > Project Settings > Time > Fixed Timestep.

The reason is stability. A physics solver integrates forces over a time slice, and its accuracy depends on that slice being small and predictable. Feed it a variable frame time and identical situations resolve differently on different hardware: a stack of crates that settles on a desktop explodes on a phone that hitched for 200 milliseconds.

So Unity decouples them. However long the frame took, physics advances in uniform 0.02s bites. If a frame took 0.05s, the engine runs the step twice and carries the remainder. If a frame took 0.008s, physics may not step at all.

Everything else in this lesson follows from that one decision.

2. Rigidbody and Collider do different jobs

Two components, constantly confused.

  • A Collider is a shape: box, sphere, capsule, mesh. It defines what space is solid. On its own it is static geometry, walls and floors that never move.
  • A Rigidbody makes an object dynamic: it gains mass, gravity, velocity, and is moved by the solver.

Collider alone means immovable scenery. Collider plus Rigidbody means a thing that falls and gets pushed. Rigidbody with no Collider means it falls through everything, because nothing gives it a shape to collide with.

A collider marked Is Trigger stops being solid and becomes a detector: things pass through it and you get OnTriggerEnter instead of OnCollisionEnter. That is how checkpoints and pickup zones work.

One performance rule up front: never move a static collider. Unity optimizes on the assumption they hold still, and shifting one forces an expensive rebuild of its data. If it must move, give it a Rigidbody marked kinematic.

3. Move it with the solver, not around it

The most common physics bug: an object has a Rigidbody, and you move it by writing transform.position. That teleports it. It skips the solver entirely, so it passes through walls, arrives with no velocity, and produces no believable collision.

Once something has a Rigidbody, the Rigidbody owns its position.

private Rigidbody rb;
private Vector3 input;

private void Awake() => rb = GetComponent<Rigidbody>();

private void Update()        // read input on the frame clock
    => input = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));

private void FixedUpdate()   // act on the physics clock
{
    rb.AddForce(input * 20f);            // accelerate
    // rb.MovePosition(rb.position + v); // kinematic-style, still swept
    // transform.position += v;          // WRONG: teleports past walls
}

Note the split: input is polled in Update because a key press lives for one frame, then applied in FixedUpdate because that is where physics listens. AddForce respects mass; MovePosition moves deliberately but still sweeps for collisions.

4. Interpolation: smooth at any frame rate

Physics updates 50 times a second. Your monitor may draw 144. So for most frames, the object has not moved since the last physics step, and you render it in a stale position. The result is subtle stutter, most visible on the object the camera follows.

The fix is one dropdown. Set the Rigidbody's Interpolate field:

  • None: render exactly where physics left it. Correct, and visibly steppy above 50fps.
  • Interpolate: smooth between the previous two physics positions. Smooth, at the cost of showing a position one physics step behind.
  • Extrapolate: predict ahead from current velocity. No lag, but it guesses, so it visibly overshoots on impacts.

The practical rule: turn Interpolate on for the player and anything the camera watches closely, and leave everything else on None. It costs nothing in gameplay terms, since it changes only what you draw, never what the solver computes. Enabling it on hundreds of objects is wasted work.

5. Tunneling and continuous collision detection

A bullet travelling 100 metres per second moves 2 metres per physics step. If the wall is 0.2m thick, the bullet is in front of it at one step and behind it at the next. The solver only tests at discrete moments, so it never saw a collision. The bullet passes through the wall. This is tunneling.

The Rigidbody's Collision Detection mode decides how hard the engine looks:

  • Discrete: test at each step's position. Cheapest, and tunnels on fast objects. The default.
  • Continuous: sweep the shape along its path against static colliders.
  • Continuous Dynamic: sweep against moving colliders too. Most expensive.
  • Continuous Speculative: cheaper sweeping approach, also works for rotation.

Set Continuous Dynamic on the fast object itself, not on everything in the level. Sweeping is real CPU work, and turning it on globally is a classic way to halve your frame rate for no benefit.

Cheap alternative for projectiles: skip Rigidbodies entirely and Physics.Raycast along the path each step.

6. Collision callbacks and layers

Contacts arrive as callbacks, fired after the solver has resolved the step, so the data describes an outcome, not a prediction.

private void OnCollisionEnter(Collision c)   // solid contact
{
    if (c.relativeVelocity.magnitude > 5f) PlayCrash();
    Debug.Log(c.contacts[0].point);
}

private void OnTriggerEnter(Collider other)  // passed through a trigger
{
    if (other.CompareTag("Player")) Collect();
}

OnCollisionEnter gives you a Collision with contact points and impact velocity. OnTriggerEnter gives you only the other Collider. Use CompareTag rather than other.tag == "Player", which allocates a string.

For a pair to report anything, at least one of them needs a Rigidbody. Two static colliders touching produce silence, which is a very common cause of "my trigger does not fire".

The scaling tool is the layer collision matrix (Project Settings > Physics). Untick pairs that can never interact and the engine stops testing them at all. Bullets that only ever hit enemies and walls should not be tested against every pickup in the level.

7. Where physics cost actually comes from

Physics gets blamed for frame drops it did not cause. The real costs are specific.

CostWhyFix
Mesh colliderstest against every triangleapproximate with box/capsule/sphere
Non-convex mesh colliderscannot be dynamic, very costlyconvex, or primitives
Continuous detection everywheresweeps every steponly on genuinely fast objects
Moving static collidersrebuilds acceleration structuresadd a kinematic Rigidbody
Everything collides with everythingquadratic pair testsprune the layer matrix
Timestep too smallmore steps per second0.02 is fine for most games

The timestep is a tempting dial and a dangerous one. Halving it to 0.01 doubles physics work per second. Worse, if a step takes longer than the timestep, the engine tries to catch up by running more steps, which takes longer still. That feedback loop is the death spiral, and Maximum Allowed Timestep exists to cap it: past that budget physics simply falls behind in slow motion rather than freezing the game.

8. When not to use physics at all

A rigidbody simulation is the right answer for tumbling debris, stacked crates, vehicles, and ragdolls. It is often the wrong answer for a player character.

Players expect precise, responsive, slightly unrealistic movement: instant stops, air control, no sliding on slopes. A Rigidbody gives you momentum and friction fighting exactly those expectations, which is why so much time is lost tuning drag to stop a character skating. Unity ships CharacterController for this: it sweeps and collides, but it is not simulated, so you move it directly and it does what you say.

The honest rule: use physics where emergent behavior is the point, and hand-authored motion where feel is the point. Many shipped games use a CharacterController for the player and Rigidbodies for everything they knock over.

And a determinism warning: Unity's physics is not deterministic across platforms or even reliably across runs. Never build lockstep multiplayer or replay systems on the assumption that it is.

9. How one frame drives physics

The engine accumulates elapsed time and spends it in fixed 0.02s steps, so a slow frame runs several and a fast frame may run none. Interpolation then decides what you actually see.

flowchart TD
  A["frame took N seconds"] --> B["add N to the accumulator"]
  B --> C["accumulator >= 0.02s?"]
  C --> D["yes: run FixedUpdate, solve, fire collision callbacks"]
  D --> E["subtract 0.02 and check again"]
  E --> C
  C --> F["no: physics is done for this frame"]
  F --> G["Update and LateUpdate run"]
  G --> H["Interpolate on? draw between last two physics positions"]
  H --> I["render"]

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. Why does Unity run physics on a fixed 0.02s timestep instead of once per rendered frame?
    • To cap physics at 50 objects per scene
    • Because the GPU cannot render faster than 50fps
    • So the solver gets uniform time slices, making results stable and hardware-independent
    • To leave every other frame free for rendering
  2. An object has a Rigidbody and you move it with `transform.position += delta`. What goes wrong?
    • It teleports, skipping the solver, so it passes through walls with no collision
    • Nothing; this is the recommended way to move a Rigidbody
    • It moves at half speed because physics halves the delta
    • Unity throws a runtime exception
  3. A bullet moving 100 m/s passes straight through a thin wall. The targeted fix is:
    • Increase the bullet's mass
    • Set the bullet's Collision Detection to Continuous Dynamic
    • Turn on Interpolate for the bullet
    • Make the wall a trigger
  4. Your Rigidbody player looks slightly steppy at 144fps even though physics is fine. Best fix?
    • Lower Fixed Timestep to 0.005
    • Move the movement code into LateUpdate
    • Switch the player to a mesh collider
    • Set the Rigidbody's Interpolate to Interpolate
  5. Your trigger volume never fires OnTriggerEnter when a wall passes through it. Most likely cause?
    • Neither object has a Rigidbody, so the pair is never tested
    • Triggers only work in Update, not FixedUpdate
    • Trigger callbacks need the objects to share a tag
    • OnTriggerEnter only fires for objects with mesh colliders

Related lessons

Math
intermediate

Symmetry Groups: Crystals, Conservation Laws, and Neural Networks

Group theory earns its keep when a symmetry argument settles a physical question no calculation was going to answer. This lesson covers group actions and counting up to symmetry, why crystals cannot have five-fold rotation and what happened when one did, Noether's link between symmetry and conservation, and how the same idea is built into modern networks.

10 steps·~15 min
Programming
intermediate

Benchmarks That Hold Up, and Knowing When to Stop

A benchmark is an experiment, and most are badly designed enough to produce confident wrong answers. This lesson covers what a measurement must control to mean anything, the ways microbenchmarks lie including code the compiler deletes, how to catch regressions in continuous integration despite noisy machines, and how to recognise the point where optimising stops paying.

7 steps·~11 min
Programming
intermediate

Where Time Actually Goes: The Six Usual Suspects

Slow software is slow for a short list of reasons, and each one has a signature you can recognise before you find the code. This lesson covers the six recurring bottleneck classes, waiting on I/O, chatty queries, allocation pressure, lock contention, memory access patterns and serialisation, with the symptom that identifies each and the fix that actually works.

7 steps·~11 min
Programming
intermediate

How Profilers Work, and How to Read a Flame Graph

A profiler is not a neutral observer: sampling and instrumentation see different things, distort the program in different ways, and answer different questions. This lesson covers how each works, why CPU time and wall-clock time give opposite answers, and how to read a flame graph correctly, including the axis that means nothing and is misread constantly.

7 steps·~11 min