Physics Puzzle
Design the cause, let physics deliver the effect — Chain Reaction
"You don't solve a physics puzzle. You set up the conditions for it to solve itself."
Prerequisites
| Module | What You Used From It |
|---|---|
| Module 2 - Platformer | Basic physics: gravity, velocity, acceleration, collision detection, fixed timestep physics loops |
Week 1: History & Design Theory
The Origin
Physics puzzles became a mainstream genre with the release of Angry Birds in 2009, but the lineage runs deeper. The Incredible Machine (1993) let players build Rube Goldberg contraptions from gears, ropes, and trampolines. Crush the Castle (2009) pioneered the slingshot-and-destruction formula that Angry Birds would refine into a cultural phenomenon. What all these games share is a design philosophy: the player sets up conditions, then watches physics resolve the outcome. The satisfaction comes not from precise execution but from prediction and surprise — you think you know what will happen when you launch that projectile, and then the structure collapses in a way that is completely logical but not quite what you expected.
How the Genre Evolved
World of Goo (2D Boy, 2008): A construction-based physics puzzle where you build structures from living goo balls that serve as both building material and structural joints. It proved that physics puzzles could be artistic, emotional, and mechanically deep simultaneously.
Angry Birds (Rovio, 2009): Simplified the physics puzzle to its most accessible form: aim a slingshot, launch a bird, destroy a structure full of pigs. It became one of the best-selling mobile games in history by making physics intuitive and the feedback loop immediate.
Cut the Rope (ZeptoLab, 2010): Inverted the typical physics puzzle by giving the player a tool of subtraction rather than addition. Instead of launching something, you cut ropes and let gravity plus momentum do the rest.
Human: Fall Flat (No Brakes Games, 2016): Brought physics puzzles into 3D with a wobbly ragdoll character whose imprecise controls are the point. It proved that physics-based interaction does not need to be precise to be engaging.
What Makes It "Great"
A great physics puzzle trusts its physics engine. The player should be able to look at a level, form a hypothesis about what will happen if they take an action, and then test that hypothesis. When the result matches their prediction, they feel smart. When it surprises them, the surprise should be explainable. The best physics puzzles embrace the emergent chaos: no two attempts play out identically because tiny differences cascade into different results.
The Essential Mechanic
Setting up conditions and letting physics resolve the outcome — the player designs the cause, physics delivers the effect.
Week 2: Build the MVP
What You're Building
An Angry Birds-style physics puzzle game where the player launches projectiles from a slingshot at destructible structures. The game uses a physics simulation for rigid bodies, collisions, and destruction. Levels consist of structures made from blocks of different materials (wood, stone, ice) that break apart when hit with enough force.
Core Concepts (Must Implement)
1. Physics Engine Integration
A physics engine handles rigid body simulation: objects have mass, velocity, and angular velocity. They collide with each other, stack under gravity, and respond to applied forces.
function create_physics_world():
world = PhysicsWorld(gravity={x: 0, y: -9.81})
return world
function create_block(world, x, y, width, height, material):
body = world.create_body(
type: DYNAMIC,
position: {x, y},
shape: Rectangle(width, height),
density: material.density,
friction: material.friction,
restitution: material.bounciness
)
body.material = material
body.health = material.health
return body
materials = {
"wood": {density: 0.5, friction: 0.6, bounciness: 0.1, health: 50},
"stone": {density: 2.0, friction: 0.8, bounciness: 0.05, health: 150},
"ice": {density: 0.3, friction: 0.1, bounciness: 0.2, health: 25}
} Why it matters: The physics engine is the core of the entire game. You are not writing collision detection from scratch — you are using an existing engine as a tool. Understanding how to configure rigid bodies is the fundamental skill.
Click and drag from the slingshot (left side) to aim. A dotted trajectory arc shows where the ball will go. Release to launch. The ball arcs under gravity and hits the stacked blocks on the right. Click "Reset" to try again.
2. Trajectory Prediction / Aiming Arc
Before the player releases the slingshot, the game shows a predicted trajectory as a dotted line. This helps the player aim without guessing.
PREDICTION_STEPS = 60
PREDICTION_TIMESTEP = 0.05
function calculate_trajectory(launch_position, launch_velocity):
points = []
pos = launch_position.copy()
vel = launch_velocity.copy()
for i in 0..PREDICTION_STEPS:
points.append(pos.copy())
vel.y += GRAVITY * PREDICTION_TIMESTEP
pos.x += vel.x * PREDICTION_TIMESTEP
pos.y += vel.y * PREDICTION_TIMESTEP
if pos.y <= GROUND_Y:
points.append({pos.x, GROUND_Y})
break
return points
function draw_trajectory(points):
for i in 0..points.length:
if i % 3 == 0:
draw_circle(points[i], radius=2, color=WHITE, alpha=0.5) Why it matters: The aiming arc bridges the gap between the player's intent and the physics simulation. Without it, aiming is pure guesswork. The prediction only simulates gravity (not collisions), so the player knows where the projectile will go but not exactly what happens on impact — preserving the surprise that makes physics puzzles satisfying.
3. Destructible Structures
Blocks have a health value. When a collision applies enough force, the block takes damage. If health reaches zero, it breaks. Different materials have different thresholds.
function on_collision(body_a, body_b, collision_info):
impact_force = collision_info.impulse_magnitude
for body in [body_a, body_b]:
if body.has("health"):
damage = calculate_damage(impact_force, body.material)
body.health -= damage
if body.health <= 0:
destroy_block(body)
else:
crack_level = 1.0 - (body.health / body.material.max_health)
update_crack_sprite(body, crack_level)
function destroy_block(body):
spawn_debris_particles(body.position, body.material)
physics_world.remove_body(body) Why it matters: Destructible structures turn a projectile launcher into a puzzle game. The player must read the structure: stone blocks at the base are hard to destroy directly, but if you can knock out the wooden supports, gravity will collapse everything.
4. Material Properties
Different materials behave differently under physics simulation. Wood is light and breaks easily. Stone is heavy and durable but devastating when it falls. Ice is fragile and slippery. These properties are data-driven.
material_definitions = {
"wood": {
density: 0.5, friction: 0.6, restitution: 0.1,
health: 50, damage_threshold: 10, damage_multiplier: 1.0,
color: BROWN, debris_count: 4
},
"stone": {
density: 2.0, friction: 0.8, restitution: 0.05,
health: 150, damage_threshold: 40, damage_multiplier: 0.5,
color: GRAY, debris_count: 6
},
"ice": {
density: 0.3, friction: 0.1, restitution: 0.2,
health: 25, damage_threshold: 5, damage_multiplier: 2.0,
color: LIGHT_BLUE, debris_count: 8
}
} Why it matters: Data-driven material properties mean you can tune the entire game's feel by changing numbers, not code. This approach makes it trivial to add new materials without writing new collision logic.
Three columns of blocks: wood (brown, light), stone (gray, heavy), and ice (blue, fragile). Click "Drop Ball" to drop a ball on each column. Adjust density and health sliders to see how materials react differently. Wood breaks easily, stone barely moves, ice shatters.
5. Scoring Based on Efficiency
The player earns a score based on how efficiently they complete each level. Fewer projectiles used means a higher score. Star ratings provide clear goals.
function calculate_score(level, projectiles_used, targets_destroyed, total_targets):
if targets_destroyed < total_targets:
return {score: 0, stars: 0}
base_score = 1000
unused = level.max_projectiles - projectiles_used
projectile_bonus = unused * 500
destruction_bonus = blocks_destroyed * 50
total = base_score + projectile_bonus + destruction_bonus
return {score: total, stars: calculate_stars(projectiles_used, level)} Why it matters: Scoring transforms a binary puzzle into a spectrum of mastery. The star rating system provides a clear, universal language for quality of solution.
6. Level Clear Detection
The game must determine when a level is complete: all targets are destroyed and the physics simulation has settled.
SETTLE_VELOCITY_THRESHOLD = 0.1
function is_physics_settled(world):
for body in world.dynamic_bodies:
speed = body.velocity.magnitude()
if speed > SETTLE_VELOCITY_THRESHOLD:
return false
return true
function check_level_clear(world, level):
if not is_physics_settled(world):
return PENDING
remaining_targets = world.bodies.filter(b => b.tag == "target" AND b.alive)
if len(remaining_targets) == 0:
return VICTORY
elif player.projectiles_remaining == 0:
return DEFEAT
else:
return PENDING Why it matters: Level clear detection must be patient. If you check immediately after impact, the structure might still be collapsing. The settled-check pattern is a common technique in physics-based games.
7. Slingshot / Launch Mechanic
The player drags backward from the slingshot to set the angle and power. The drag distance and direction map directly to the launch force vector.
SLINGSHOT_POSITION = {x: 100, y: 300}
MAX_PULL_DISTANCE = 150
LAUNCH_FORCE_MULTIPLIER = 10.0
function on_pointer_down(position):
if distance(position, slingshot.anchor) < GRAB_RADIUS:
slingshot.is_aiming = true
function on_pointer_move(position):
if not slingshot.is_aiming: return
pull = slingshot.anchor - position
if pull.magnitude() > MAX_PULL_DISTANCE:
pull = pull.normalized() * MAX_PULL_DISTANCE
slingshot.pull_vector = pull
launch_velocity = pull * LAUNCH_FORCE_MULTIPLIER
trajectory = calculate_trajectory(slingshot.anchor, launch_velocity)
draw_trajectory(trajectory)
function on_pointer_release():
if not slingshot.is_aiming: return
slingshot.is_aiming = false
launch_velocity = slingshot.pull_vector * LAUNCH_FORCE_MULTIPLIER
slingshot.current_projectile.apply_impulse(launch_velocity) Why it matters: The slingshot mechanic is the player's only point of interaction. The drag-and-release input maps human gesture to physics force in a way that feels natural: pull back farther for more power, change the angle by dragging in a different direction.
Stretch Goals
- Multiple projectile types: Different projectiles with unique abilities (one that splits, one that explodes, one that accelerates).
- Joints and constraints: Connect blocks with breakable joints so structures sway and deform before breaking.
- Slow-motion replay: After each shot, offer a slow-motion replay of the destruction.
- Level editor: Let the player place blocks, targets, and the slingshot to create custom levels.
MVP Spec
| Element | Scope |
|---|---|
| Physics | Rigid body simulation with gravity, collision, and friction |
| Slingshot | Drag-and-release input with visual pull-back feedback |
| Trajectory | Dotted-line preview of projectile path during aiming |
| Materials | 3 types: wood (light, weak), stone (heavy, strong), ice (light, fragile) |
| Destruction | Health-based block breaking on collision impact |
| Scoring | Star rating based on projectiles used |
| Clear detection | Wait for physics to settle, then check targets |
| Projectiles | 3-5 projectiles per level |
Deliverable
A playable physics puzzle game with 5-8 levels where the player launches projectiles from a slingshot at destructible structures. The game must use a physics simulation, include at least three material types, show a trajectory preview while aiming, detect level completion only after physics settles, and display a star rating based on efficiency.
Analogies by Background
For Backend Developers
| Concept | Analogy |
|---|---|
| Physics Engine | Like using a database engine — you configure schemas (bodies), set properties, and let the engine handle queries (collisions, forces). |
| Trajectory Prediction | Like a dry-run mode for migrations — simulate without committing to see the result. |
| Destructible Structures | Like cascading deletes in a relational database — removing one entity causes dependents to collapse. |
| Material Properties | Like configuration profiles for different environments — the same code behaves differently based on config. |
| Level Clear Detection | Like eventual consistency checks — you poll until the system quiesces, then read the final state. |
For Frontend Developers
| Concept | Analogy |
|---|---|
| Physics Engine | Like using a layout engine (Flexbox, CSS Grid) — you declare what you want and the engine calculates positions. |
| Trajectory Prediction | Like a live preview in a WYSIWYG editor — the preview updates in real time before you commit. |
| Destructible Structures | Like a DOM tree where removing a parent causes children to reflow and cascade. |
| Material Properties | Like design tokens — centralized values controlling how components look and behave. |
| Slingshot Mechanic | Like a drag-and-drop interaction — grab, drag to set direction, release to trigger. |
For Data / ML Engineers
| Concept | Analogy |
|---|---|
| Physics Engine | Like using a numerical solver (SciPy) — define the system of equations and the solver computes the next state. |
| Trajectory Prediction | Like forward-propagating without backprop — run inference to see output without committing. |
| Destructible Structures | Like pruning a neural network — removing nodes causes dependent connections to collapse. |
| Material Properties | Like hyperparameter configs — the same architecture produces different behaviors based on parameters. |
| Level Clear Detection | Like waiting for distributed training to synchronize before evaluating. |
Discussion Questions
- Determinism vs. Chaos: Physics engines can produce slightly different results from the same initial conditions. Should a physics puzzle be perfectly deterministic?
- Readability of Failure: When a player's shot fails, they need to understand why. How do you design visual feedback so the player can read what happened?
- The Tutorial Problem: Physics puzzles seem intuitive but players often struggle with the force-drag relationship. How would you teach through level design rather than text?
- Physics as Content: In a physics puzzle, the engine generates emergent outcomes the designer did not script. How does this change the designer's role?