Skip to main content
Back to module
Game Prototyping & Systems · Mechanics

Simple physics

Reading50mLesson 2 of 3 in this module

Add gravity, ground contact, jumping and variable jump height to a canvas platformer.

Why this matters

Jumping is the signature verb of a whole genre, and "game feel" lives in a handful of numbers: how hard gravity pulls, how fast the jump starts, what happens when the player lets go of the button. You do not need a physics engine to get a great jump. You need three ideas (velocity, acceleration, ground contact) and the discipline to tune them as design values, not magic numbers.

Position, velocity, acceleration

Each frame:

  1. acceleration changes velocity,
  2. velocity changes position.

Gravity is a constant downward acceleration. With y growing downwards on a canvas, gravity is positive:

const GRAVITY = 1800;   // pixels per second per second

function applyPhysics(dt) {
  player.vy += GRAVITY * dt;    // velocity changes by acceleration
  player.y  += player.vy * dt;  // position changes by velocity
}

Updating velocity first and then position with the new velocity is called semi-implicit Euler integration. It is simple and stable enough for most games. Because both lines multiply by dt, the jump is roughly the same height at 30 fps and 144 fps (here about 90 px vs 98 px; a fixed timestep makes it identical on every machine).

Landing on the ground

Without a floor the player falls forever. The simplest floor is a single line:

const GROUND_Y = 180;

if (player.y + player.h >= GROUND_Y) {
  player.y = GROUND_Y - player.h;   // snap on top of the ground
  player.vy = 0;                    // stop falling
  player.onGround = true;
} else {
  player.onGround = false;
}

Two things matter. Snap the player to the surface so they never sink in. Zero the velocity, or gravity keeps building speed while they stand still and the next step off a ledge becomes a sudden plunge. For platforms, apply the same idea with the AABB test from the last lesson: if the player is falling (vy > 0) and overlaps a platform, put them on top of it.

The jump

A jump is an instant upward velocity, applied only when standing:

const JUMP_SPEED = 600;

function jump() {
  if (!player.onGround) return;   // no infinite air jumps
  player.vy = -JUMP_SPEED;        // negative = up on a canvas
  player.onGround = false;
}

Gravity then slows the rise, stops it at the peak and pulls the player back down. Physics gives you the shape for free: the peak height is JUMP_SPEED² / (2 × GRAVITY). With 600 and 1800 that is 100 pixels, and the time to the peak is 600 / 1800 = 0.33 seconds. Designers often work backwards: choose the height and time to peak you want, then solve for gravity and jump speed. The GDC talk "Building a Better Jump" walks through this method.

Variable jump height

In many platformers, tapping jump gives a hop and holding it gives a full jump. A simple way to get that: when the player releases the button while still rising fast, cut the upward speed.

const JUMP_CUT = 0.5;

function releaseJump() {
  const minRise = -JUMP_SPEED * JUMP_CUT;
  if (player.vy < minRise) player.vy = minRise;   // still rising fast: slow down
}

If the player is already falling or rising slowly, nothing changes, so a late release does not cause a strange mid-air stop.

Feel tricks worth knowing

  • Coyote time: allow a jump for about 0.1 s after walking off a ledge. Players perceive this as fair, not as cheating.
  • Jump buffering: remember a jump press made just before landing and perform it on landing.
  • Higher gravity when falling: many games multiply gravity by 1.5 to 2 on the way down for a snappier arc.
  • Terminal velocity: cap vy so long falls stay readable.

Each of these is a few lines once the basic state (vy, onGround) exists. Add them one at a time and playtest each.

Treat numbers as design data

Put tuning values in one place, name them, and show them on screen or in a debug panel while you play:

const TUNING = { GRAVITY: 1800, JUMP_SPEED: 600, JUMP_CUT: 0.5, MAX_FALL: 900 };

A designer who can change jump height in five seconds will try twenty variations; one who must hunt through code will try two.

Common mistakes

  • Gravity with the wrong sign. On a canvas, down is positive.
  • Not resetting vy on landing, so speed keeps building while standing.
  • Jumping without checking onGround, which gives infinite jumps.
  • Forgetting dt in either line, which makes the jump depend on frame rate.
  • Setting onGround only to true, never back to false when walking off a ledge.

Quick recap

  • Acceleration changes velocity; velocity changes position, both times dt.
  • Snap to the ground, zero vy, track onGround.
  • Jump = set vy to a negative speed, only from the ground.
  • Releasing early cuts upward speed for variable height.
  • Name your tuning values and tweak them while playing.

Try it

Open the Do tab to implement applyPhysics, jump and releaseJump for a canvas platformer.

Also in this lesson: