Module 27

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

ModuleWhat You Used From It
Module 2 - PlatformerBasic 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.

Interactive: Trajectory Prediction & Slingshot

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.

Shots: 0 Drag from slingshot to aim

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.

Interactive: Material Properties

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

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

MVP Spec

ElementScope
PhysicsRigid body simulation with gravity, collision, and friction
SlingshotDrag-and-release input with visual pull-back feedback
TrajectoryDotted-line preview of projectile path during aiming
Materials3 types: wood (light, weak), stone (heavy, strong), ice (light, fragile)
DestructionHealth-based block breaking on collision impact
ScoringStar rating based on projectiles used
Clear detectionWait for physics to settle, then check targets
Projectiles3-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

ConceptAnalogy
Physics EngineLike using a database engine — you configure schemas (bodies), set properties, and let the engine handle queries (collisions, forces).
Trajectory PredictionLike a dry-run mode for migrations — simulate without committing to see the result.
Destructible StructuresLike cascading deletes in a relational database — removing one entity causes dependents to collapse.
Material PropertiesLike configuration profiles for different environments — the same code behaves differently based on config.
Level Clear DetectionLike eventual consistency checks — you poll until the system quiesces, then read the final state.

For Frontend Developers

ConceptAnalogy
Physics EngineLike using a layout engine (Flexbox, CSS Grid) — you declare what you want and the engine calculates positions.
Trajectory PredictionLike a live preview in a WYSIWYG editor — the preview updates in real time before you commit.
Destructible StructuresLike a DOM tree where removing a parent causes children to reflow and cascade.
Material PropertiesLike design tokens — centralized values controlling how components look and behave.
Slingshot MechanicLike a drag-and-drop interaction — grab, drag to set direction, release to trigger.

For Data / ML Engineers

ConceptAnalogy
Physics EngineLike using a numerical solver (SciPy) — define the system of equations and the solver computes the next state.
Trajectory PredictionLike forward-propagating without backprop — run inference to see output without committing.
Destructible StructuresLike pruning a neural network — removing nodes causes dependent connections to collapse.
Material PropertiesLike hyperparameter configs — the same architecture produces different behaviors based on parameters.
Level Clear DetectionLike waiting for distributed training to synchronize before evaluating.

Discussion Questions

  1. Determinism vs. Chaos: Physics engines can produce slightly different results from the same initial conditions. Should a physics puzzle be perfectly deterministic?
  2. 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?
  3. 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?
  4. 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?