Projects/Build a Physics Engine

Build a Physics Engine

Start with a Vec2 that can add and take a dot product and end with a world that drops a box onto the ground and lets it settle at rest. Every lesson is one concrete spec with exact values: why semi-implicit Euler beats explicit, the impulse that makes a head-on bounce reverse, the minimum-penetration axis from SAT, and the r x n terms that turn a contact into spin.

44 lessonsMedium~20 min / lessonRigid-body dynamicsCollision detectionImpulse resolution
The project

What you'll build over the next 44 lessons

Over 44 lessons you build a working 2D rigid-body physics engine from scratch: a Vec2 math kit (add, subtract, scale, dot, length, normalize, and the 2D scalar cross), particles you move with numerical integration (explicit vs semi-implicit Euler, forces, gravity, a force accumulator, and a fixed timestep), rigid bodies with mass and inverse mass so a static body has infinite mass and never moves, shapes (circle, AABB, convex polygon) with world transforms, collision detection that returns an exact contact normal and penetration depth for every shape pair (circle-circle, AABB-AABB, circle-AABB, polygon-polygon and circle-polygon via the Separating Axis Theorem), impulse-based resolution with restitution and positional correction, rotation with moment of inertia and contact-point impulses that produce spin, Coulomb friction, and a world step that integrates, detects, and resolves every frame.

By the end you have an importable engine and a runnable, asset-free text demo: it steps a small scene under gravity and prints each body's position over time, ending with a box that drops onto the ground and settles at rest without tunneling through it. The engine is deterministic and its public API is fully tested, so every behavior is pinned to an exact value.

This is a teaching-grade engine built around the standard impulse-with-restitution design that Box2D and similar 2D engines use: sequential-impulse resolution over a per-frame contact list, with positional correction for sinkage. It is honest about what it does not do - it resolves each contact at a single point, derives a Coulomb friction impulse but leaves wiring it into the resolver as the first extension, uses a small fixed number of solver iterations rather than a full warm-started constraint solver, has no continuous collision detection (very fast bodies can tunnel), no joints or resting/sleeping, and a simple grid-free broadphase. What you finish with is the honest core that production 2D engines extend with friction, warm starting, two-point manifolds, and richer constraints.

build-a-physics-engine / lesson-01.md
Lesson 01 · A 2D vector kit

A 2D vector you can add

A physics engine is arithmetic on 2D vectors, so that is where everything begins. Today you build the Vec2 type and its first operation, addition, so every later lesson has positions and velocities to work with.

The goal

Create a Vec2 value type with X and Y components and an addition that sums them componentwise.

Start here - the target
TO DO
Scenario: Adding two 2D vectors
Giventhe vectors {1, 2} and {3, 4}
Whenthey are added
Thenthe result is {4, 6}
AndAdd({-1, 5}, {2, -3}) is {1, 2}
Background

Every quantity in a physics engine - a position, a velocity, a force, a contact normal - is a 2D vector: a pair of numbers you can do arithmetic on. Before any of the interesting motion or collision code can exist, that value type has to exist, along with the operations that combine vectors. The most basic of those is addition, which sums the two components independently: moving a point by an offset, or combining two velocities, is just adding vectors.

Use plain float64 components so results stay exact for the clean inputs the specs use. Keep Add a pure function that returns a brand-new Vec2 rather than mutating its inputs - the rest of the engine leans on vectors being simple, copyable values, and that convention starts today.

Make it work
// the value type every position, velocity, and force will be
type Vec2 struct{ X, Y float64 }
// componentwise sum, returns a new vector
func Add(a, b Vec2) Vec2 {
return Vec2{ /* X + X, Y + Y */ }
}
CheckpointDONE
You have a Vec2 type and can add two of them. Commit and stop here.
Scope & extensions

Where this project stops - and where to go next

A genuinely working 2D rigid-body engine - semi-implicit integration, mass and inverse mass, circle/box/convex-polygon collision with exact contact manifolds via SAT, and impulse resolution with restitution, positional correction, and rotation behind a world step that settles a scene - but contacts are resolved at a single point, a Coulomb friction impulse is derived yet not applied in the resolver, and there is no warm starting, continuous collision, joints, or sleeping.

Extend it next
  • Apply the Coulomb friction impulse inside the contact resolver so sliding is damped - the friction term is built and tested but not yet wired into the resolve step
  • Add two-point (clipped) contact manifolds for polygon collisions so a box resting flat is constrained at both corners at once, not a single point
  • Add contact warm starting across frames so stacks stay stable with far fewer solver iterations
  • Add continuous collision detection (or a per-step speed limit) so fast, small bodies cannot tunnel through thin geometry in one step
  • Replace the brute-force pairwise broadphase with a spatial grid or sweep-and-prune as body counts grow
  • Add joints (pin, spring, distance) and a resting/sleeping system so idle stacks stop consuming solver time
Recommended reading

Books & references that go deeper

  • The classic rigid-body dynamics series. Part 3 derives the impulse-with-restitution collision response, including the r x n rotational terms, that the resolution chapter is built around.

  • The Box2D author's GDC talks on sequential impulses, the contact solver, and positional correction - the design this project follows for resolving a per-frame contact list.

  • A step-by-step impulse-engine tutorial: manifolds, normal and penetration, impulse resolution, positional correction, and friction - the same arc, worked in code.

  • Real-Time Collision Detection · Christer Ericson

    The reference for the geometry: closest-point tests, AABBs, and the Separating Axis Theorem used for the polygon collision detection in chapter four.

  • Game Physics Engine Development · Ian Millington

    A full book that builds a particle engine and then a rigid-body engine in the same order this project does - integration first, then contacts, then rotation.

  • Advanced Character Physics · Thomas Jakobsen

    The Hitman/Verlet paper - a different integration and constraint approach worth reading once you finish, to see the road not taken.