LEARN GAME PHYSICS FROM SCRATCH
Learn Game Physics from Scratch
Goal: To build a 2D rigid-body physics engine from the ground up, starting with a review of high-school physics and translating the core concepts of motion, force, and collision directly into code.
Why Learn Game Physics from Scratch?
Most game developers use existing physics engines like Box2D or PhysX. While powerful, they can be “black boxes.” Building your own teaches you the fundamental principles that govern all of them. This knowledge is a superpower for debugging, creating unique gameplay mechanics, and truly mastering game development.
The key thing to remember is that game physics is not real physics. It’s a set of clever approximations designed to look believable and run fast, while remaining stable.
After completing these projects, you will:
- Have a deep, intuitive understanding of Newtonian mechanics.
- Be able to write a stable, time-step-based simulation.
- Implement collision detection algorithms for various shapes.
- Write impulse-based collision resolution code to make objects bounce and react realistically.
- Understand the physics of rotation, including torque and friction.
- Have your very own, working 2D physics engine.
Core Concept Analysis: Physics for a Game Loop
Real-world physics is continuous. Game physics is discrete, calculated one “frame” or “time step” at a time. This is the most important difference.
1. The Language: Vectors
Everything in physics—position, velocity, force—is a vector. In 2D, a vector is simply a pair of numbers (x, y). You’ll need to be comfortable with basic vector math:
- Addition/Subtraction:
(x1, y1) + (x2, y2) = (x1+x2, y1+y2) - Scalar Multiplication:
(x, y) * s = (x*s, y*s) - Magnitude (Length):
sqrt(x*x + y*y) - Normalization (creating a unit vector of length 1)
- Dot Product: Projects one vector onto another. Incredibly useful for collision response.
- Cross Product: In 2D, a useful trick to get a perpendicular vector.
2. The Simulation Loop: Kinematics & Integration
This is the heart of your engine. In each step of your game loop, you will update the state of every object.
┌──────────────────────────────────────────────────────────┐
│ START OF PHYSICS STEP (dt) │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ 1. ACCUMULATE FORCES │
│ (e.g., Gravity adds a downward force to every object) │
│ force = (0, mass * 9.8) │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ 2. NUMERICAL INTEGRATION │
│ │
│ // Use force to find acceleration (Newton's 2nd Law) │
│ acceleration = force / mass │
│ │
│ // Use acceleration to find new velocity (Integrate) │
│ velocity += acceleration * dt │
│ │
│ // Use velocity to find new position (Integrate) │
│ position += velocity * dt │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ 3. DETECT & RESOLVE COLLISIONS │
│ (Check for intersections and make objects bounce) │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ END OF PHYSICS STEP │
│ (Render objects at new positions) │
└──────────────────────────────────────────────────────────┘
- Delta Time (
dt): The small amount of time that passes in each step of the simulation (e.g., 1/60th of a second). It is the “secret sauce” that makes everything work. Using a fixeddtis crucial for stability. - Numerical Integration: The process of updating position and velocity over a time step. The method shown above is called Explicit Euler integration, and it’s the simplest way to get started.
3. Key Physics Concepts
- Rigid Body: The central object in our simulation. It has properties like:
mass: How heavy it is.position(vector): Where it is.velocity(vector): How fast it’s moving.angle(scalar): What direction it’s facing.angularVelocity(scalar): How fast it’s spinning.
- Force: A push or a pull (a vector). Gravity is a constant downward force. A rocket thruster is a force applied in the direction the rocket is facing.
- Impulse: An “instantaneous” change in velocity. We don’t use massive “repulsion forces” to resolve collisions, as that’s unstable. Instead, when two objects hit, we calculate and apply an impulse to make them bounce apart perfectly.
- Momentum:
p = mass * velocity. In a closed system, momentum is conserved, which is the key principle behind our collision resolution calculations. - Torque & Moment of Inertia: These are the rotational equivalents of Force and Mass. Applying a
forceat the center of an object makes it move; applying it off-center creates atorquethat makes it spin. Themoment of inertiadescribes how resistant an object is to being spun.
Project List
These projects are a step-by-step guide to building your own 2D physics engine from scratch. You will need a simple 2D graphics library to visualize your results. Raylib (for C/C++) or the HTML5 Canvas API (for JavaScript) are excellent choices.
Project 1: The Bouncing Ball (Kinematics)
- File: LEARN_GAME_PHYSICS_FROM_SCRATCH.md
- Main Programming Language: C++ (with Raylib)
- Alternative Programming Languages: JavaScript (with HTML5 Canvas), C (with SDL2)
- Coolness Level: Level 2: Practical but Forgettable
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 1: Beginner
- Knowledge Area: Kinematics / Numerical Integration
- Software or Tool: A simple 2D graphics library (e.g., Raylib)
- Main Book: “Game Physics Engine Development, 2nd Edition” by Ian Millington
What you’ll build: A simple program that shows a single circle moving under the influence of gravity and bouncing off the edges of the screen.
Why it teaches game physics: This is the “Hello, World!” of physics programming. It forces you to implement the three most critical components: a game loop, the concept of delta time (dt), and the Euler integration formula that updates an object’s position and velocity over time.
Core challenges you’ll face:
- Creating a game loop → maps to understanding how to run a simulation step-by-step
- Implementing vector math → maps to creating a simple Vec2 class or struct with basic operations
- Applying constant acceleration (gravity) → maps to the first half of the integration step (
velocity += gravity * dt) - Updating position from velocity → maps to the second half of the integration step (
position += velocity * dt) - Screen-edge collision → maps to simple
ifstatements to check boundaries and reverse velocity
Key Concepts:
- The Game Loop: “Game Programming Patterns” by Robert Nystrom - Chapter 2.
- Vectors: Any high-school math resource on 2D vectors.
- Euler Integration: “Game Physics Engine Development” by Ian Millington - Chapter 4.
Difficulty: Beginner Time estimate: Weekend Prerequisites: Basic programming proficiency in your chosen language.
Real world outcome: A window will open, and you’ll see a circle fall from the top of the screen, bounce off the bottom edge, and continue bouncing, eventually settling if you add a simple damping factor.
Implementation Hints:
- Create a
Bodyclass/struct. It should containVec2 position,Vec2 velocity,Vec2 acceleration, andfloat radius. - In your main loop, before you update anything, calculate your delta time (
dt). For simplicity, you can start with a fixed value like1.0f / 60.0f. - In your update function:
body.velocity.y += 9.8f * dt;(Applying gravity)body.position += body.velocity * dt;
- After updating, check for boundary collisions:
if (body.position.y + body.radius > screen_height)thenbody.velocity.y *= -1;(invert y-velocity). Do this for all four walls.
- Draw the circle at its new position.
Learning milestones:
- A circle appears and falls down the screen → Gravity is working.
- The circle’s speed increases as it falls → Your integration of velocity is correct.
- The circle bounces off the screen edges → Your boundary checks are working.
- The simulation runs at the same speed regardless of your computer’s performance → You have correctly implemented a fixed timestep.
Project 2: Cannonball Trajectories (Forces)
- File: LEARN_GAME_PHYSICS_FROM_SCRATCH.md
- Main Programming Language: C++ (with Raylib)
- Alternative Programming Languages: JavaScript (with HTML5 Canvas)
- Coolness Level: Level 2: Practical but Forgettable
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 1: Beginner
- Knowledge Area: Dynamics / Forces & Mass
- Software or Tool: Your existing code from Project 1.
- Main Book: “Physics for Game Developers” by David M. Bourg
What you’ll build: An interactive version of Project 1. Start with a ball at rest. When the user clicks the screen, apply a large force to the ball, launching it towards the click location. Add multiple balls with different masses to see how they react differently to the same force.
Why it teaches game physics: This project introduces Newton’s Second Law (F=ma) in a tangible way. You’ll move from just having constant acceleration (gravity) to calculating acceleration from forces, which is the core of a real physics engine.
Core challenges you’ll face:
- Accumulating forces → maps to creating a
forcevector on your rigid body that gets reset to zero each frame - Implementing Newton’s Second Law → maps to calculating
acceleration = force / mass - Applying one-time forces (impulses) → maps to applying a large force for a single frame to represent a kick or a launch
- Handling mass → maps to seeing that for the same force, a heavier object will have less acceleration
Key Concepts:
- Newton’s Laws of Motion: “Physics for Game Developers” - Chapter 3.
- Force Accumulation: “Game Physics Engine Development” - Chapter 5.
Difficulty: Beginner Time estimate: Weekend Prerequisites: Project 1.
Real world outcome:
A simple simulation where you can click to “fire” cannonballs. You’ll see that a heavy “cannonball” requires a much bigger “kick” to fly as far as a lighter one, demonstrating F=ma visually.
Implementation Hints:
- Add
float massandVec2 forceto yourBodystruct. - Change your integration step. It should now be:
body.force.y += body.mass * 9.8f;(Apply gravity force)body.acceleration = body.force / body.mass;body.velocity += body.acceleration * dt;body.position += body.velocity * dt;body.force = Vec2(0, 0);(Crucial: clear forces for the next frame!)
- In your input handling, when the user clicks:
- Calculate a direction vector from the ball’s position to the mouse position.
- Normalize this vector.
- Multiply it by a large scalar (e.g., 5000.0) to create a launch force.
- Call a function like
body.AddForce(launch_force). This function simply doesbody.force += launch_force;.
Learning milestones:
- Clicking applies a force and moves the ball → You have connected input to the force accumulator.
- A ball with
mass=10moves slower than a ball withmass=1when the same force is applied → You have correctly implemented Newton’s Second Law. - You can apply multiple forces (e.g., gravity + a “wind” force) and they combine correctly → Your force accumulator is working.
Project 3: Circle-Circle Collision Detection & Resolution
- File: LEARN_GAME_PHYSICS_FROM_SCRATCH.md
- Main Programming Language: C++ (with Raylib)
- Alternative Programming Languages: JavaScript (with HTML5 Canvas)
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 2: Intermediate
- Knowledge Area: Collision Detection / Collision Response
- Software or Tool: Your existing code.
- Main Book: “Real-Time Collision Detection” by Christer Ericson
What you’ll build: A simulation with multiple balls that can collide with each other. When they collide, they should bounce off each other in a physically plausible way.
Why it teaches game physics: This is the biggest and most important step. You’ll implement the two core phases of any physics engine: detection (are they touching?) and response (if so, what do we do?). You’ll learn that the “response” is not a force, but an instantaneous change in velocity called an impulse.
Core challenges you’ll face:
- Pairwise checking → maps to a nested loop that checks every body against every other body
- Circle-vs-Circle detection → maps to checking if the distance between two centers is less than the sum of their radii
- Calculating relative velocity → maps to understanding motion from the perspective of one of the colliding objects
- Calculating and applying an impulse → maps to using the impulse formula, which depends on relative velocity, masses, and the collision normal, to change the bodies’ velocities
Key Concepts:
- Collision Detection Primitives: “Real-Time Collision Detection” - Chapter 4.
- Impulse-based Collision Resolution: “Game Physics Engine Development” - Chapter 9. A fantastic, clear explanation.
- Conservation of Momentum: The core principle behind the impulse calculation.
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Project 2, solid grasp of vector math (dot product is essential here).
Real world outcome: A “pool break” simulation. You can launch one ball into a cluster of other balls, and they will scatter and bounce off each other realistically.
Implementation Hints:
- Detection:
- In your main loop, iterate through all pairs of bodies
(i, j). - Calculate distance vector
d = body[j].position - body[i].position. - If
d.magnitude_squared() < (body[i].radius + body[j].radius)^2, they are colliding. (Use squared distances to avoidsqrt).
- In your main loop, iterate through all pairs of bodies
- Response:
- If a collision is detected, get the collision normal:
normal = d.normalize(). - Calculate relative velocity along the normal:
relative_velocity_normal = dot(body[j].velocity - body[i].velocity, normal). - If
relative_velocity_normal > 0, they are moving apart, so do nothing. - Calculate the impulse
j = -(1 + restitution) * relative_velocity_normal / (1/mass_i + 1/mass_j). Start withrestitution(bounciness) = 1. - Apply the impulse to each body along the normal:
body[i].velocity -= (j / mass_i) * normal;body[j].velocity += (j / mass_j) * normal;
- If a collision is detected, get the collision normal:
Learning milestones:
- Colliding circles change color or stop → Your collision detection is working.
- Colliding circles bounce apart → Your impulse calculation is partially working.
- A heavy ball hitting a light ball sends the light ball flying, while the heavy ball is barely affected → Your mass calculations in the impulse are correct.
- You can adjust a
restitutionvariable from 0 (inelastic, thud) to 1 (perfectly elastic, bounce) → You have full control over the collision response.
Project 4: Rotational Dynamics & AABB Collision
- File: LEARN_GAME_PHYSICS_FROM_SCRATCH.md
- Main Programming Language: C++ (with Raylib)
- Alternative Programming Languages: JavaScript (with HTML5 Canvas)
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 3: Advanced
- Knowledge Area: Rotational Dynamics / AABB Collision
- Software or Tool: Your existing engine.
- Main Book: “Game Physics Engine Development, 2nd Edition” by Ian Millington
What you’ll build: Extend your engine to support rectangles (Axis-Aligned Bounding Boxes, or AABBs for now). Add rotational properties (angle, angularVelocity, torque) and implement the logic to make them spin when a force is applied off-center. Implement AABB-vs-AABB collision detection and resolution.
Why it teaches game physics: This project introduces rotation, which is essential for most games. You’ll learn the rotational equivalents of force (torque), mass (moment of inertia), and velocity (angular velocity), and see how they are integrated in the same way as their linear counterparts.
Core challenges you’ll face:
- Adding rotational properties to your
Body→ maps tofloat angle,float angularVelocity,float torque,float momentOfInertia - Calculating Moment of Inertia → maps to finding the formula for the moment of inertia of a solid rectangle
- Integrating rotation → maps to
angularVelocity += (torque / momentOfInertia) * dt; angle += angularVelocity * dt; - Applying torque → maps to
torque = cross(offset_from_center, force) - AABB-vs-AABB collision detection → maps to a simple and fast geometric check
Key Concepts:
- Rotational Dynamics: “Physics for Game Developers” - Chapter 6.
- Moment of Inertia: Formulas are widely available online; for a 2D solid box of width
wand heighth:I = (1/12) * mass * (w^2 + h^2). - AABB Collision: “Real-Time Collision Detection” by Christer Ericson - Chapter 4.
Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Project 3.
Real world outcome: You can spawn rectangles, click on a corner to apply a force, and watch them realistically spin and fly across the screen, colliding with other rectangles.
Implementation Hints:
- Extend your
Bodyclass. Add the rotational properties. Calculate and store themomentOfInertiawhen the body is created. - Extend your
AddForcefunction. It now needs a second parameter: the point where the force is applied (in world coordinates).- Inside, you’ll still do
body.force += force;. - You’ll also calculate the torque:
radius = point - body.position; torque += cross(radius, force);. In 2D, the cross product of two vectors(rx, ry)and(fx, fy)is a scalarrx*fy - ry*fx.
- Inside, you’ll still do
- In your integration step, add the rotational updates and remember to clear the torque each frame:
body.torque = 0;. - For AABB-vs-AABB detection (where
AandBare boxes withminandmaxcorners):- Collision occurs if
A.max.x > B.min.xANDA.min.x < B.max.xANDA.max.y > B.min.yANDA.min.y < B.max.y.
- Collision occurs if
- Resolution for AABBs is more complex than circles because the collision normal is always along an axis (up, down, left, or right). You need to find the axis of minimum penetration. For now, you can approximate it and apply the impulse from Project 3.
Learning milestones:
- Applying a central force moves a box without rotation → Linear dynamics still work.
- Applying a force to a corner makes the box spin and move → You have successfully implemented torque.
- A ‘thin’ box is easier to spin than a ‘square’ box of the same mass → Your moment of inertia calculation is correct.
- Two non-rotating boxes collide and bounce apart correctly → Your AABB detection and resolution are working.
Project 5: Building a Ragdoll
- File: LEARN_GAME_PHYSICS_FROM_SCRATCH.md
- Main Programming Language: C++ (with Raylib)
- Alternative Programming Languages: JavaScript (with HTML5 Canvas)
- Coolness Level: Level 5: Pure Magic (Super Cool)
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 4: Expert
- Knowledge Area: Constraints / Composite Objects
- Software or Tool: Your existing engine.
- Main Book: N/A, this is usually learned from online tutorials and papers (e.g., Thomas Jakobsen’s “Advanced Character Physics”).
What you’ll build: A simple 2D ragdoll. You will connect several rectangle bodies together using “distance constraints” or “revolute joints” to form a humanoid shape. Then you can drop it, throw it around, and watch it flop and tumble realistically.
Why it teaches game physics: This project introduces constraints, which are the basis for almost all advanced physics simulation. Ropes, chains, character joints, and vehicle suspensions are all built from constraints. It forces you to move beyond simple pairwise collisions to a system where multiple bodies are interconnected.
Core challenges you’ll face:
- Designing a constraint system → maps to creating a
Constraintclass that holds references to two bodies and a desired distance - Solving constraints → maps to iteratively adjusting the positions of the connected bodies to satisfy the constraint
- Integrating constraints with the solver → maps to running the constraint solver after integration but before rendering
- Building a hierarchy → maps to connecting rectangles for a torso, head, arms, and legs
Key Concepts:
- Position-Based Dynamics: A modern approach where constraints directly modify positions instead of using forces. Thomas Jakobsen’s papers are the classic source.
- Iterative Solvers: You can’t solve all constraints at once. You loop through them multiple times per frame, and the system converges towards a stable solution.
Difficulty: Expert Time estimate: 2-3 weeks Prerequisites: Project 4.
Real world outcome: You will have a stick-figure character in your engine that you can pick up with the mouse, fling across the screen, and watch as it tumbles over other objects in a physically plausible, often hilarious, way.
Implementation Hints:
- Start with the simplest constraint: a distance constraint (a “stick”). It connects two bodies,
AandB, and has arest_length. - After you’ve updated all body positions with your integrator (
position += velocity * dt), you run the constraint solver. - The solver loops (e.g., 5-10 times) through all constraints. In each iteration, for each distance constraint:
- Calculate the vector between the two bodies:
delta = B.position - A.position. - Calculate the current distance:
dist = delta.magnitude(). - Calculate the error:
error = dist - rest_length. - Calculate the correction vector:
correction = delta.normalize() * error * 0.5. - Move the bodies apart/together:
A.position += correction; B.position -= correction;.
- Calculate the vector between the two bodies:
- Build your ragdoll by creating several rectangle bodies and connecting them with these distance constraints. For example, connect the “head” to the “torso”, the “upper arm” to the “torso”, etc.
Learning milestones:
- Two circles connected by a line maintain their distance → Your basic distance constraint is working.
- A chain of connected circles hangs and swings like a rope → Your iterative solver is correctly propagating the constraints.
- Your ragdoll character holds its shape when dragged around → You have successfully built a composite physical object.
- The ragdoll realistically collapses and tumbles when dropped on other objects → Your entire physics engine—integration, collision, resolution, and constraints—is working together.
Project Comparison Table
| Project | Difficulty | Time | Core Concept | Fun Factor |
|---|---|---|---|---|
| 1. The Bouncing Ball | Beginner | Weekend | Integration, Kinematics | ★★★☆☆ |
| 2. Cannonball Trajectories | Beginner | Weekend | Forces, Mass, Dynamics | ★★★★☆ |
| 3. Circle-Circle Collision | Intermediate | 1-2 weeks | Impulse, Momentum | ★★★★★ |
| 4. Rotational Dynamics | Advanced | 1-2 weeks | Torque, Moment of Inertia | ★★★★☆ |
| 5. Building a Ragdoll | Expert | 2-3 weeks | Constraints, Joints | ★★★★★ |
Recommendation
Start with Project 1: The Bouncing Ball. Do not skip this. The concepts it teaches—the fixed-timestep game loop and Euler integration—are the absolute bedrock of everything that follows. Spend time tweaking the gravity and watching the numbers in a debugger. Your goal is to build an intuition for how velocity and position change over discrete time steps.
Once the bouncing ball feels solid, move directly to Project 2: Cannonball Trajectories and then Project 3: Circle-Circle Collision. These three projects form a trilogy that covers the complete, fundamental lifecycle of a physics engine: move things with forces, detect when they hit, and make them bounce. Mastering these three will give you 80% of the knowledge you need to understand any physics engine.
Summary
- Project 1: The Bouncing Ball (Kinematics): C++ (with Raylib)
- Project 2: Cannonball Trajectories (Forces): C++ (with Raylib)
- Project 3: Circle-Circle Collision Detection & Resolution: C++ (with Raylib)
- Project 4: Rotational Dynamics & AABB Collision: C++ (with Raylib)
- Project 5: Building a Ragdoll: C++ (with Raylib)