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
- Physics advances in fixed timesteps; variable steps make it non-deterministic and unstable. See Game Loops.
- Semi-implicit Euler is the standard integrator: update velocity first, then position. It's stable enough and cheap.
- Collision detection is two-phase: a cheap broad phase (spatial partitioning, AABBs) then an exact narrow phase (SAT, GJK).
- Static / kinematic / dynamic body types have completely different costs and behaviors — choosing wrong is the most common setup error.
- Tunneling happens when a fast object skips past a thin collider between steps; CCD fixes it at a cost.
- Solvers are iterative — stacked bodies, long chains, and extreme mass ratios expose their limits.
- Determinism requires fixed steps, fixed iteration counts, consistent ordering, and identical floating-point behavior.
- Character controllers usually bypass rigid-body physics entirely, because good movement feel isn't physical.
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:
- Sphere/circle vs. sphere — compare distance to summed radii. Nearly free.
- AABB vs. AABB — overlap on every axis. Very cheap.
- SAT (Separating Axis Theorem) — for convex polygons: if any axis separates them, they don't intersect.
- GJK + EPA — general convex shapes; GJK detects intersection, EPA finds penetration depth.
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
- Game Loops & ECS — Fixed timesteps, the prerequisite for stable physics
- Unity —
Rigidbody,FixedUpdate, and PhysX - Godot —
CharacterBody,move_and_slide, and collision layers - Unreal Engine — Chaos physics and
CharacterMovementComponent - Multiplayer Netcode — Where determinism becomes mandatory
- Game AI — Movement, steering, and navigation on top of physics
- Algorithms & Data Structures — Spatial partitioning structures
- Performance Optimization — Profiling the physics budget