Physics Engine and Collision Detection
Physics Engine and Collision Detection
Definition: A system that simulates realistic movement (gravity, momentum, forces) and detects when game objects overlap or collide, so games don’t need to hand-code physical behavior from scratch.
How It Works
- Applies forces (gravity, velocity, friction) to objects each frame, tied to Frame Rate and Delta Time so simulation speed stays consistent
- Detects collisions using simplified shapes (“colliders”) like boxes, spheres, and capsules wrapped around visual models, since checking exact visual mesh geometry every frame would be far too slow
- Resolves collisions by adjusting position and velocity so objects don’t visually overlap or pass through each other, applying an impulse proportional to mass and closing speed
- Collision detection runs in two phases: a cheap broad phase that rules out most pairs quickly, and a precise narrow phase that only runs on pairs the broad phase couldn’t rule out
- Rigid body simulation tracks mass, velocity, angular velocity, and applies Newtonian integration (
velocity += acceleration * dt,position += velocity * dt) every physics step - Colliders are often marked “static” (never moves, like a wall), “dynamic” (affected by forces, like a falling crate), or “kinematic” (moved directly by code, like a moving platform, but not affected by forces) so the engine can skip unnecessary work on each category
- Collision layers and masks let designers declare in advance which categories of objects should ever be tested against each other, pruning entire classes of pairs before the broad phase even runs
- Sleeping is an optimization where objects at rest for several consecutive steps stop being simulated entirely until something (a nearby impact) wakes them back up
Under the Hood
The broad phase exists purely to avoid running the expensive narrow-phase math on every possible pair of objects in the scene.
Worked example 1: broad phase pair reduction
- Given: a scene with 500 objects, and naive collision checking tests every possible pair
- Step: number of pairs without any broad phase = 500 × 499 / 2 = 124,750 pair checks per physics step
- Step: a spatial grid divides the scene into cells; if objects are evenly spread, each object only shares a cell (or neighboring cell) with roughly 5 others on average, so broad phase produces about 500 × 5 / 2 = 1,250 candidate pairs
- Answer: the narrow phase, the expensive precise check, only runs on those ~1,250 pairs instead of 124,750, a roughly 99% reduction in expensive work per step
Worked example 2: fixed timestep collision stability
- Given: a ball moving at 50 units/sec toward a wall, physics updates at a fixed 60Hz (16.67ms per step, so ~0.833 units per step)
- Step: at frame N the ball is 0.5 units from the wall; the next 0.833-unit step would move it 0.333 units past the wall’s surface if collision were checked only at the start and end of the step (a “tunneling” case)
- Step: continuous collision detection sweeps the ball’s full path for that step, not just its start and end position, and finds the exact time within the step (t ≈ 0.6 of the step) where contact occurs
- Answer: the ball stops exactly at the wall surface instead of tunneling through it; this swept-shape approach is specifically why fast-moving small objects (bullets, thrown items) often need continuous collision detection instead of simple per-frame overlap checks
Worked example 3: solver iterations and stack stability
- Given: a stack of 5 crates resting on top of each other, each contact needs an impulse computed that accounts for every other contact in the stack
- Step: a single solver pass at the bottom contact doesn’t yet know about the corrected impulse from the contact above it, so with only 1 iteration the stack visibly sinks or jitters as errors accumulate frame to frame
- Step: increasing solver iterations to 8-10 lets the impulse calculation propagate through the whole stack within a single physics step, each iteration refining every contact’s impulse using the results of the previous iteration
- Answer: more iterations cost more CPU time per step but converge closer to a physically correct resting state; this is the direct trade-off exposed by a physics engine’s “solver iteration count” setting
Core Algorithms
| Stage | Common algorithm | What it does |
|---|---|---|
| Broad phase | Sweep and prune | Sorts object bounds along one axis, only compares neighbors whose ranges overlap |
| Broad phase | Spatial grid / hash | Buckets objects into fixed-size cells, only compares objects sharing a cell |
| Broad phase | Bounding Volume Hierarchy (BVH) | Tree of nested bounding boxes, prunes whole branches that don’t overlap |
| Narrow phase | Separating Axis Theorem (SAT) | Tests convex shapes for a separating axis, works for polygons and boxes |
| Narrow phase | GJK (Gilbert-Johnson-Keerthi) | Iteratively finds closest points between convex shapes, used for arbitrary convex hulls |
| Continuous detection | Conservative advancement / swept volumes | Finds the exact time of impact within a step for fast-moving objects |
Collision Response Math
- The impulse that separates two colliding bodies along the contact normal is commonly computed as:
j = -(1 + restitution) * relativeVelocity . normal
/ (1/massA + 1/massB)
restitution(0 to 1) controls bounciness: 0 means the objects stick together on impact (perfectly inelastic), 1 means no energy is lost (perfectly elastic)- Given: a 2kg ball hits a 1kg ball at a closing speed of 4 units/sec along the contact normal, with restitution 0.5
- Step:
j = -(1 + 0.5) * (-4) / (1/2 + 1/1) = 6 / 1.5 = 4 - Answer: that impulse of 4 is applied in opposite directions to each ball, scaled by their inverse mass, so the lighter ball (1kg) gets pushed back roughly twice as hard per unit of impulse as the heavier one (2kg)
Why It Matters
- Hand-coding realistic physics for every interaction would be enormously time-consuming, physics engines make believable movement and interaction practical to build
- The broad phase/narrow phase split is what makes physics simulation scale to hundreds or thousands of objects instead of collapsing under pairwise comparison cost
- Consistent, deterministic physics is required for networked multiplayer, where every client’s simulation has to agree on the outcome of a collision
- Sleeping and layer/mask pruning are why physics-heavy games can simulate large, mostly-static worlds without the frame cost growing linearly with total object count
Common Pitfalls
- Using overly complex colliders (a collider matching the exact visual mesh) when a simple box, sphere, or capsule would be visually indistinguishable and far cheaper to compute
- Running physics calculations at a variable frame rate without fixing the physics update rate, causing inconsistent or unstable simulation behavior, or even different outcomes on different hardware
- Not using continuous collision detection for small, fast-moving objects, letting them tunnel through thin walls or floors between physics steps
- Applying forces or setting velocity directly inside a rendering-rate update instead of the fixed physics step, causing jittery or frame-rate-dependent motion
- Stacking many dynamic rigid bodies (a tower of crates) without adequate solver iterations, producing visible jitter or slow sinking as the solver fails to fully resolve all the contacts each step
- Marking objects that never move as “dynamic” instead of “static,” forcing the broad phase to needlessly re-check their bounds every single step
- Setting collision layers/masks incorrectly, so bullets collide with other bullets, or the player’s own attack hitbox collides with the player, producing bugs that only show up in specific gameplay situations
- Ignoring collision event ordering when multiple contacts resolve in the same step, causing inconsistent outcomes (a crate pushed simultaneously by two other crates) between runs
- Assuming physics results will match exactly across different machines or platforms without disabling any hardware-specific floating point optimizations, a real source of desync bugs in networked physics games
Comparison
| Technique | Cost | Accuracy | Typical use |
|---|---|---|---|
| Discrete collision (check position each step) | Cheap | Can tunnel through thin objects at high speed | Most objects, slow-to-moderate speed |
| Continuous collision detection (swept shapes) | More expensive | Catches fast-moving thin-object collisions | Bullets, thrown objects, fast projectiles |
| Box/sphere/capsule colliders | Cheap | Approximate | Almost all gameplay collision |
| Mesh colliders (exact geometry) | Expensive | Exact | Static level geometry only, rarely dynamic objects |
| Sleeping / deactivated bodies | Nearly free | N/A, skipped entirely | Objects at rest for multiple consecutive steps |
Example
Box2D (2D) and Unity’s built-in PhysX-based physics engine (3D) both simulate gravity and collisions so a jumping character falls and lands on platforms convincingly without custom-coded math. Unreal Engine uses Chaos Physics for its rigid body and destruction simulation, and Godot ships its own built-in physics engine (with an optional Jolt Physics backend in newer versions) for both 2D and 3D. All three expose the same underlying concepts to developers: rigid bodies, colliders, layers/masks, and a fixed physics tick rate, even though the internal solver implementations differ.
Common Interview Questions
- Why split collision detection into broad and narrow phases? — the broad phase cheaply eliminates the vast majority of object pairs that can’t possibly be touching, so the expensive precise check only runs on plausible candidates
- What causes tunneling, and how is it fixed? — a fast-moving object’s position at the start and end of a step doesn’t overlap the obstacle even though it passed through it mid-step; continuous (swept) collision detection checks the whole path, not just the endpoints
- Why does physics usually run at a fixed timestep instead of variable delta time? — determinism and stability, an inconsistent step size can make a stable stack of objects jitter or a solver’s iterative approximation diverge
- What’s the difference between a collider and a rigid body? — a collider defines shape for detecting overlap, a rigid body adds mass, velocity, and the forces/response needed to actually move as a result of that overlap
- Why use simplified colliders instead of the exact render mesh? — narrow-phase math on a high-poly mesh is dramatically more expensive per pair than on a box or sphere, for a difference players essentially never perceive
- What’s the difference between SAT and GJK? — SAT tests for a separating axis between two convex polygons directly, GJK iteratively finds the closest points between two convex shapes using a support function, more general but more complex
- Why do physics solvers use multiple iterations instead of solving contacts exactly in one pass? — an exact simultaneous solution for many interacting contacts is expensive; iterative approximation trades a small amount of accuracy for speed, refining toward the correct answer each pass
FAQ
- Do all colliding objects need a full rigid body? — no, “trigger” colliders detect overlap and fire an event (like a pickup zone) without applying any physical response at all
- Why do physics engines usually run at a lower, fixed rate than rendering? — stability and determinism matter more than visual smoothness for physics, and a fixed step is cheaper to make reproducible across machines
- Can two static colliders ever generate a collision event? — typically no, most engines skip pairs where both bodies are static since neither can move as a result
- What’s collision layers/masks for? — a way to tell the broad phase to skip entire categories of pairs outright (player bullets never need to test against enemy bullets, for instance), cutting work before the broad phase even runs
- Is collision detection the same as collision response? — no, detection just determines whether and where two shapes overlap; response is the separate step of deciding what happens next (bounce, stop, destroy, trigger an event)
- What wakes a sleeping physics object back up? — a new contact from another moving body, a direct force or velocity change applied by game code, or a change to the object’s own collider