Tutorials › Game Physics Simple Mode

Game Physics

Learn how real-seeming motion works in games: velocity, gravity, friction, and collision detection — the building blocks of every platformer and arcade game.

1

Velocity: Speed with Direction

In games, we don't just move things by saying "go right." We use velocity — a number that says how fast something moves AND which direction. A positive vx moves right, a negative vx moves left. Same for vy: positive goes down, negative goes up. Each frame, we add the velocity to the position.
0 / 29 lines
Loading editor...
let vx = 2, vy = -1; setup: size(400 300) draw: background(midnightblue) // Add velocity to position each frame x += vx y += vy // Wrap around edges if (x > width) x = 0 if (x < 0) x = width if (y > height) y = 0 if (y < 0) y = height // Draw the ball fill(gold) noStroke() circle(x y 15) // Show the velocity fill(white) textSize(14) text("vx = " + vx + " (moving right)" 10 20) text("vy = " + vy + " (moving up!)" 10 40) text("Position: (" + Math.round(x) + ", " + Math.round(y) + ")" 10 280)
Try it!

Change vx to -3 and vy to 2. Which direction does the ball go now? Try (0, 3) for straight down!

2

Gravity: Acceleration That Pulls Down

Gravity isn't a speed — it's an acceleration. That means it changes the velocity over time. Each frame, we add a small gravity value to vy. The ball starts slow, then falls faster and faster — just like in real life! This is how every platformer game works.
0 / 31 lines
Loading editor...
let vy = 0; let gravity = 0.3; setup: size(400 300) draw: background(midnightblue) // Gravity increases vy each frame vy += gravity // Velocity moves the ball y += vy // Reset when it falls off screen if (y > height + 20) { y = 0 vy = 0 // Draw the ball fill(tomato); noStroke(); circle(x y 20); // Show what's happening fill(white); textSize(14); text("vy = " + vy.toFixed(1) 10 20); text("gravity adds " + gravity + " to vy each frame" 10 40); text("The ball gets FASTER as it falls!" 10 280); }
Try it!

Try changing gravity to 0.1 (moon gravity!) or 1.0 (super heavy). How does it feel different?

3

Bouncing Off the Floor

When a ball hits the floor, we need to reverse its vy to make it go up. But in real life, bounces lose energy — the ball doesn't bounce back to the same height. We simulate this by multiplying vy by something like -0.8. The minus flips direction, and the 0.8 reduces the speed by 20%.
0 / 39 lines
Loading editor...
let vy = 0; let gravity = 0.4; setup: size(400 300) draw: background(midnightblue) // Apply gravity vy += gravity y += vy // Bounce off the floor! if (y > height - 15) { y = height - 15 vy = vy * -0.8; // Reverse AND lose 20% energy // Draw the ball fill(gold); noStroke(); circle(x y 15); // Draw the "floor" stroke(white); strokeWeight(2); line(0 height - 1 width height - 1); // Info noStroke(); fill(white); textSize(14); text("vy = " + vy.toFixed(1) 10 20); text("Each bounce loses 20% energy" 10 40); text("Click to reset!" 10 280); } mousePressed: y = 30 vy = 0
Try it!

Change -0.8 to -1.0 for a perfect bounce (no energy loss). Try -0.5 for a heavy, dead bounce.

4

Friction: Slowing Down

Friction makes things slow down over time. Instead of subtracting speed, we multiply vx by a number close to 1, like 0.99. Each frame, the speed drops a tiny bit. Over many frames, it adds up! This is how you make things slide to a stop. Let's add arrow keys so you can push the ball around.
0 / 44 lines
Loading editor...
let vx = 0, vy = 0; let friction = 0.98; let gravity = 0.3; setup: size(400 300) draw: background(midnightblue) // Arrow keys add velocity (thrust!) if (keyIsDown("ArrowLeft")) vx -= 0.5 if (keyIsDown("ArrowRight")) vx += 0.5 if (keyIsDown("ArrowUp")) vy -= 0.5 // Gravity pulls down vy += gravity // Friction slows horizontal movement vx *= friction // Move the ball x += vx y += vy // Bounce off walls if (x < 12) { x = 12; vx *= -0.7; } if (x > width - 12) { x = width - 12; vx *= -0.7; } // Bounce off floor if (y > height - 12) { y = height - 12 vy *= -0.7 vx *= 0.95; // Floor friction too! // Draw fill(mediumseagreen); noStroke(); circle(x y 12); fill(white); textSize(14); text("Arrow keys to push!" 10 20); text("vx: " + vx.toFixed(2) 10 280); }
Try it!

Change friction from 0.98 to 0.90 — it stops much faster! Try 1.0 for no friction (ice!).

5

Circle vs Circle Collision

How do you know if two circles are touching? Measure the distance between their centers using dist(). If the distance is less than the sum of their radii, they're overlapping! Here, the ball gets pushed away from a mouse-controlled circle.
0 / 57 lines
Loading editor...
let vx = 0, vy = 0; let ballR = 15; let cursorR = 25; let gravity = 0.2; setup: size(400 300) draw: background(midnightblue) // Apply gravity and friction vy += gravity vx *= 0.99 // Move the ball ballX += vx ballY += vy // Floor bounce if (ballY > height - ballR) { ballY = height - ballR vy *= -0.75 // Wall bounce if (ballX < ballR) { ballX = ballR; vx *= -0.8; } if (ballX > width - ballR) { ballX = width - ballR; vx *= -0.8; } // COLLISION: check distance between centers let d = dist(mouseX mouseY ballX ballY); let minDist = cursorR + ballR; if (d < minDist && d > 0) { // Push the ball away from the cursor let pushX = (ballX - mouseX) / d; let pushY = (ballY - mouseY) / d; vx += pushX * 3; vy += pushY * 3; } // Draw cursor circle noFill(); stroke(dodgerblue); strokeWeight(2); circle(mouseX mouseY cursorR); // Draw the ball fill(d < minDist ? "tomato" : gold); noStroke(); circle(ballX ballY ballR); // Info fill(white); textSize(13); text("Distance: " + Math.round(d) + "px" 10 20); text("Colliding: " + (d < minDist ? "YES!" : "no") 10 40); text("Push the ball around with your mouse!" 10 280); }
6

Multiple Balls with Physics

Let's bring it all together! An array of balls, each with its own position and velocity. Every frame: apply gravity, move, bounce off walls, and check collisions with the mouse. This is the foundation of how real game physics engines work.
0 / 63 lines
Loading editor...
setup: size(400 300) for (let i = 0; i < 8; i++) { balls.push({ x: random(30 370), y: random(30 100), vx: random(-2 2), vy: 0, r: random(8 18), color: "hsl(" + (i * 45) + ", 75%, 60%)" }) } draw: background(midnightblue) for (let i = 0; i < balls.length; i++) { let b = balls[i] // Gravity b.vy += 0.25 // Friction b.vx *= 0.999 // Move b.x += b.vx b.y += b.vy // Bounce off walls if (b.x < b.r) { b.x = b.r; b.vx *= -0.8; } if (b.x > width - b.r) { b.x = width - b.r; b.vx *= -0.8; } // Bounce off floor if (b.y > height - b.r) { b.y = height - b.r b.vy *= -0.8 b.vx *= 0.95 // Mouse push let d = dist(mouseX mouseY b.x b.y); if (d < 30 + b.r && d > 0) { b.vx += (b.x - mouseX) / d * 2; b.vy += (b.y - mouseY) / d * 2; } // Draw fill(b.color); noStroke(); circle(b.x b.y b.r); } fill(white); textSize(14); text("Move your mouse to push the balls!" 80 20); noFill(); stroke(white); strokeWeight(1); circle(mouseX mouseY 30); }
Try it!

Try changing the gravity to 0 for a zero-gravity space scene! Or add more balls by changing 8 to 20.

What to try next

  • Add a ceiling bounce so balls can't fly off the top of the screen
  • Make balls collide with EACH OTHER — check dist() between every pair of balls
  • Add a click-to-launch feature: click anywhere to spawn a new ball with velocity toward the mouse
  • Build a simple platformer character: arrow keys for left/right, up to jump (only when on the ground!)