2D Elastic Collision
Two disks bounce off walls and each other with mass-weighted impulse response.
Paste into main.js in the editor, then click Restart.
Complete example
javascript
if (!state.init) {
state.init = true;
state.p1 = { x: 150, y: h / 2, vx: 120, vy: 0, r: 30, mass: 1, color: '#8B5CF6' };
state.p2 = { x: w - 150, y: h / 2, vx: -80, vy: 0, r: 20, mass: 0.5, color: '#EF4444' };
}
const p1 = state.p1, p2 = state.p2;
p1.x += p1.vx * dt;
p1.y += p1.vy * dt;
p2.x += p2.vx * dt;
p2.y += p2.vy * dt;
function bounceWalls(p) {
if (p.x < p.r) { p.x = p.r; p.vx *= -1; }
if (p.x > w - p.r) { p.x = w - p.r; p.vx *= -1; }
if (p.y < p.r) { p.y = p.r; p.vy *= -1; }
if (p.y > h - p.r) { p.y = h - p.r; p.vy *= -1; }
}
bounceWalls(p1);
bounceWalls(p2);
const dx = p2.x - p1.x, dy = p2.y - p1.y;
const dist = Math.sqrt(dx * dx + dy * dy);
const minDist = p1.r + p2.r;
let colliding = false;
if (dist < minDist && dist > 0) {
colliding = true;
const nx = dx / dist, ny = dy / dist;
const dvx = p1.vx - p2.vx, dvy = p1.vy - p2.vy;
const dvn = dvx * nx + dvy * ny;
if (dvn > 0) {
const impulse = (2 * dvn) / (p1.mass + p2.mass);
p1.vx -= impulse * p2.mass * nx;
p1.vy -= impulse * p2.mass * ny;
p2.vx += impulse * p1.mass * nx;
p2.vy += impulse * p1.mass * ny;
}
const overlap = minDist - dist;
p1.x -= overlap * 0.5 * nx;
p1.y -= overlap * 0.5 * ny;
p2.x += overlap * 0.5 * nx;
p2.y += overlap * 0.5 * ny;
}
return {
particles: [
{ x: p1.x, y: p1.y, r: p1.r, color: colliding ? '#F59E0B' : p1.color, label: 'm1' },
{ x: p2.x, y: p2.y, r: p2.r, color: colliding ? '#F59E0B' : p2.color, label: 'm2' },
],
vectors: [
{ x: p1.vx * 0.3, y: p1.vy * 0.3, ox: p1.x, oy: p1.y, color: '#22C55E' },
{ x: p2.vx * 0.3, y: p2.vy * 0.3, ox: p2.x, oy: p2.y, color: '#22C55E' },
],
text: {
p1_speed: Math.hypot(p1.vx, p1.vy).toFixed(0),
p2_speed: Math.hypot(p2.vx, p2.vy).toFixed(0),
collision: colliding ? 'YES' : 'no',
},
};Collision steps
- Broad test — distance < sum of radii
- Normal — unit vector
nfrom p1 → p2 - Separating? — if relative velocity along
nis already separating (dvn ≤ 0), skip impulse - Impulse — scale by masses; apply ± along
n - Positional correction — push apart by half the overlap to reduce sinking
MATH
For equal masses head-on, velocities exchange along the contact normal. Unequal masses: heavier body keeps more of its momentum.
Try next
- Add more bodies in an array and check pairs (
i < j) - Inelastic collisions: scale impulse by restitution
e(0–1) - Show contact normal as a
vectorsarrow during overlap