Game Physics

Game physics is not a simulation of physics. It's a real-time approximation tuned to be stable, fast, and — most importantly — to feel right. A physically accurate jump arc makes a bad platformer. Engines routinely apply gravity several times stronger than Earth's, cancel momentum on landing, and let the player steer mid-air, because the goal is a control feel rather than a correct answer.

Underneath the tuning sit three problems that every physics engine solves in roughly the same way: integration (advance positions from velocities and forces), collision detection (find what's overlapping, fast, among thousands of objects), and collision response (resolve overlaps into plausible outcomes without exploding). Understanding those three explains almost every physics bug you'll encounter — objects sinking into floors, jittering against walls, or passing straight through them at speed.

TL;DR

Quick Example

A minimal 2D simulation showing the pieces in order — integrate, detect, resolve:

The four stages map directly onto what you configure in an engine: gravity and damping, collision layers (broad phase), collider shapes (narrow phase), and solver iteration counts.

Core Concepts

Integration

The difference between explicit and semi-implicit Euler is one line reordered, and it's the difference between a spring that settles and a spring that flings itself off-screen.

Body types

Static-vs-static pairs are never tested. A "static" object moved by script every frame is the classic performance mistake — it invalidates broad-phase structures that assumed it wouldn't move. Mark it kinematic.

Broad phase

Testing every pair is O(n²): a thousand objects means half a million tests per step. The broad phase reduces that to near-linear using axis-aligned bounding boxes and spatial structures.

Collision layers are the cheapest broad-phase optimization available and the one most often left unconfigured. If bullets never hit other bullets and pickups never hit each other, the layer matrix should say so — those tests then never happen at all.

Narrow phase

Exact intersection tests on the surviving pairs:

The narrow phase produces a contact manifold: the contact points, the collision normal, and the penetration depth. Everything the solver does depends on those three values being right.

Collision response

Response happens in two steps, and conflating them causes most jitter bugs.

Impulse resolution changes velocities along the contact normal, scaled by the restitution (bounciness) and the bodies' inverse masses. Position correction fixes the residual overlap that the velocity solve leaves behind — usually with Baumgarte stabilization, which pushes objects apart by a fraction of the penetration per step, and a small allowed slop so resting contacts don't vibrate.

Solvers are iterative: each contact is resolved in turn, and resolving one may violate another. More iterations means more accuracy and more CPU. Stacked boxes sinking into each other means too few iterations; jittering means position correction fighting the velocity solve.

Tunneling and CCD

Fixes, cheapest first: make colliders thicker than the fastest object travels in one step; raise the physics rate; cap velocity; or enable continuous collision detection on the specific fast objects. Never enable CCD globally — it's expensive, and almost nothing in a scene needs it.

Determinism

A deterministic simulation produces bit-identical results from identical inputs. It's required for rollback netcode, replays, and lockstep multiplayer — and it's much harder than it sounds.

Cross-platform float determinism is the hard part; teams that need it commonly use fixed-point arithmetic or a determinism-focused engine rather than trying to constrain the FPU. Same-binary determinism (replays on one platform) is much more achievable.

Character Controllers

The counterintuitive part: player movement in most games is not a rigid body.

Rigid-body characters slide down slopes, get pushed by every collision, rotate when they shouldn't, and respond sluggishly to input — all physically correct and all bad. Purpose-built character controllers instead sweep a capsule, resolve collisions by sliding along surfaces, and apply hand-authored acceleration, air control, and gravity curves.

Unity's CharacterController, Godot's CharacterBody2D/3D with move_and_slide(), and Unreal's CharacterMovementComponent are all of this kind. Reach for a rigid body when physical interaction is the mechanic — a rolling ball, a ragdoll, a physics puzzle.

Best Practices

Run physics in the fixed-step callback

FixedUpdate, _physics_process, or your own accumulator loop. Applying forces from a per-frame callback makes their magnitude depend on frame rate, which produces "the game is easier on a good PC" bugs.

Configure the collision layer matrix early

It's the single largest broad-phase win and takes minutes. Every pair of layers that can never interact should be unchecked. Always pass a layer mask to raycasts — an unfiltered raycast tests everything, including the object casting it.

Use primitive colliders wherever possible

Sphere and capsule tests are nearly free; boxes are cheap; convex hulls are moderate; concave mesh colliders are expensive and should be static-only. A complex character is a capsule for movement and, at most, a handful of primitives for hit detection.

Keep mass ratios reasonable

A solver handling a 1 kg object against a 10,000 kg object accumulates numerical error and produces jitter or explosion. Keep ratios within roughly two orders of magnitude, or make the heavy object static or kinematic.

Let bodies sleep

Physics engines deactivate bodies whose velocity stays below a threshold, and reactivate them on contact. Anything that continuously nudges a body — a tiny script force, unstable resting contact — keeps hundreds of objects awake and simulating for no reason. Check the sleep counts in the physics profiler.

Tune gravity for feel, not accuracy

Real gravity produces floaty jumps at game scale. Most platformers use two to four times 9.81, plus asymmetric rise and fall gravity, and often a short coyote-time window and jump buffering. This is authored, not simulated — and it's what players perceive as good controls.

Cache physics queries

A raycast per enemy per frame adds up quickly. Share results where enemies query the same thing, use non-allocating query variants, and stagger expensive checks across frames rather than doing all of them every step.

Common Mistakes

Moving a rigid body by setting its transform

Applying forces in the per-frame update

Using explicit Euler

Enabling CCD on everything

Concave mesh colliders on moving objects

Expecting determinism without arranging for it

FAQ

Why do my stacked boxes sink into each other?

Too few solver iterations, or too much accumulated penetration for the position-correction step to resolve. Raise the iteration count, reduce the allowed penetration slop, avoid extreme mass ratios in the stack, and check that box colliders aren't slightly overlapping at spawn. Deep stacks are genuinely hard for iterative solvers — this is a known limit, not a misconfiguration.

Why does my character jitter against a wall?

Usually the position-correction step and the velocity solve fighting each other, or a character controller re-colliding with the same surface every step. Add a small skin width or contact offset, ensure the movement code stops applying velocity into a surface it's already touching, and check for overlapping colliders at the contact point.

Should I use 2D or 3D physics for a 2D game?

2D physics, if the engine has a separate 2D pipeline (Box2D, Unity's 2D physics). It's substantially faster, avoids an entire class of bugs from stray Z-axis motion, and its API matches how you think about the problem. Using 3D physics constrained to a plane works but costs more and leaks 3D concepts into a 2D game.

How do I make fast projectiles hit reliably?

Most games don't simulate bullets as rigid bodies at all — they raycast (or shapecast) from the previous position to the new one each step and treat any hit as the impact. That's exact, cheap, and immune to tunneling. Reserve simulated projectiles for slow, arcing ones where the physical trajectory is the point.

Which physics engine should I use?

Whatever your engine ships with, until you have a specific reason otherwise. Unity uses PhysX (3D) and Box2D-derived 2D physics; Unreal uses Chaos; Godot has its own plus optional Jolt. For custom engines: Box2D for 2D, Jolt or PhysX for 3D, and Rapier in Rust. Jolt has become the strong default for new 3D work.

How do I get physics determinism across platforms?

With difficulty. You need a fixed timestep, fixed iteration counts, deterministic container iteration, and identical floating-point results — the last of which requires disabling fast-math, controlling FMA contraction, and matching instruction sets across every platform. Teams that need cross-platform lockstep usually adopt fixed-point arithmetic instead. Single-platform determinism (replays, rollback among identical binaries) is far more tractable.

Related Topics

References