Collision Detection
Axis-aligned boxes that push each other apart
Chapter goal
Detect AABB overlaps and resolve the player against solid platforms so they stand and slide instead of falling through.
How to do it
- 1
Define boxes
An AABB is {x, y, w, h}. Two boxes overlap if they overlap on both X and Y axes.
- 2
Resolve the shallow axis
When overlapping, compute penetration on X and Y; push out along the smaller penetration so corners feel right.
- 3
Mark grounded
If you resolve upward out of a platform, set grounded=true so the next chapter can allow jumps.
Live lab
Solution code updates with sliders. Tinker is your sandbox. Play runs whichever document you launch.
Live settings
Every slider injects into the engine constants for this chapter.
The chapter engine script is prewritten below. Type it line by line — each line explains why it belongs there. Matching a line advances automatically; Enter re-checks if you are stuck.
1(function () {2 "use strict";3 // Single boot — if this document is re-parsed, abandon prior work.4 if (window.__engineBooted) return;5 window.__engineBooted = true;6 let alive = true;7 window.addEventListener("pagehide", function () { alive = false; }, { once: true });8 const raf = window.requestAnimationFrame.bind(window);9 window.requestAnimationFrame = function (cb) {10 return raf(function (ts) {11 if (!alive) return;12 try { cb(ts); } catch (err) { console.error(err); alive = false; }13 });14 };1516const canvas = document.getElementById('c');17const ctx = canvas.getContext('2d');18const W = canvas.width, H = canvas.height;19const hud = document.getElementById('hud');2021const SPEED = 180;22const PLAYER_W = 26;23const PLAYER_H = 34;24const GAP = 70;2526const keys = Object.create(null);27addEventListener('keydown', e => { keys[e.code]=true; if(e.code.startsWith('Arrow')||e.code==='Space') e.preventDefault(); });28addEventListener('keyup', e => { keys[e.code]=false; });2930const player = { x: 60, y: 40, w: PLAYER_W, h: PLAYER_H, vx: 0, vy: 0, grounded: false };31const solids = [32 { x: 0, y: H - 24, w: W, h: 24 },33 { x: 80, y: H - 24 - GAP, w: 100, h: 14 },34 { x: 240, y: H - 24 - GAP * 1.4, w: 90, h: 14 },35 { x: 400, y: H - 24 - GAP * 0.9, w: 130, h: 14 },36 { x: 300, y: H - 24 - GAP * 2.1, w: 80, h: 14 },37 { x: 520, y: 80, w: 16, h: 160 },38];3940function aabb(a, b) {41 return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;42}4344function resolve(p, s) {45 const overlapX = Math.min(p.x + p.w - s.x, s.x + s.w - p.x);46 const overlapY = Math.min(p.y + p.h - s.y, s.y + s.h - p.y);47 if (overlapX < overlapY) {48 if (p.x + p.w/2 < s.x + s.w/2) p.x -= overlapX; else p.x += overlapX;49 p.vx = 0;50 } else {51 if (p.y + p.h/2 < s.y + s.h/2) { p.y -= overlapY; p.vy = 0; p.grounded = true; }52 else { p.y += overlapY; p.vy = 0; }53 }54}5556let last = performance.now();57function loop(now) {58 const dt = Math.min((now - last) / 1000, 0.05);59 last = now;6061 let ax = 0;62 if (keys['ArrowLeft']||keys['KeyA']) ax -= 1;63 if (keys['ArrowRight']||keys['KeyD']) ax += 1;64 player.vx = ax * SPEED;65 // light gravity so you fall onto platforms66 player.vy += 900 * dt;67 if (player.vy > 600) player.vy = 600;6869 player.grounded = false;70 player.x += player.vx * dt;71 for (const s of solids) if (aabb(player, s)) resolve(player, s);72 player.y += player.vy * dt;73 for (const s of solids) if (aabb(player, s)) resolve(player, s);7475 if (player.y > H + 40) { player.x = 60; player.y = 40; player.vx = 0; player.vy = 0; }7677 ctx.fillStyle = '#0b1018';78 ctx.fillRect(0, 0, W, H);7980 ctx.fillStyle = '#1a2535';81 for (const s of solids) {82 ctx.fillRect(s.x, s.y, s.w, s.h);83 ctx.strokeStyle = 'rgba(94,234,212,0.2)';84 ctx.strokeRect(s.x + 0.5, s.y + 0.5, s.w - 1, s.h - 1);85 }8687 ctx.fillStyle = player.grounded ? '#5eead4' : '#7dd3fc';88 ctx.fillRect(player.x, player.y, player.w, player.h);8990 hud.textContent = 'Chapter 6 · grounded=' + player.grounded + ' · solids=' + solids.length;91 requestAnimationFrame(loop);92}93requestAnimationFrame(loop);9495})();
Arrows/WASD — walk on platforms; collision keeps you solid. · Sliders update the play window after a short pause.