click any where on the screen and watch the balls bounce off of each other
<!DOCTYPE html>
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
resizeCanvas();
window.addEventListener("resize", resizeCanvas);
canvas.addEventListener("click", createBall);
let balls = [];
const MAX_SPEED = 28; // Disappear threshold
const SPEED_INCREASE = 1.07; // Gentler acceleration on collision
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
class Ball {
constructor(x, y, radius, color, dx, dy) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.dx = dx;
this.dy = dy;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
this.x += this.dx;
this.y += this.dy;
// Bounce off left/right edges
if (this.x - this.radius < 0) {
this.x = this.radius; // reposition inside
this.dx *= -1;
} else if (this.x + this.radius > canvas.width) {
this.x = canvas.width - this.radius;
this.dx *= -1;
}
// Bounce off top/bottom edges
if (this.y - this.radius < 0) {
this.y = this.radius;
this.dy *= -1;
} else if (this.y + this.radius > canvas.height) {
this.y = canvas.height - this.radius;
this.dy *= -1;
}
}
getSpeed() {
return Math.sqrt(this.dx * this.dx + this.dy * this.dy);
}
}
function createBall(event) {
const x = event.clientX;
const y = event.clientY;
// Smaller overall balls
const radius = Math.random() * 15 + 8;
const color = hsl(${Math.random() * 360}, 80%, 60%);
const speed = Math.random() * 4 + 1;
const angle = Math.random() * Math.PI * 2;
const dx = Math.cos(angle) * speed;
const dy = Math.sin(angle) * speed;
balls.push(new Ball(x, y, radius, color, dx, dy));
}
function handleCollisions() {
for (let i = 0; i < balls.length; i++) {
for (let j = i + 1; j < balls.length; j++) {
const b1 = balls[i];
const b2 = balls[j];
const dx = b2.x - b1.x;
const dy = b2.y - b1.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < b1.radius + b2.radius) {
// Swap velocities
const tempDx = b1.dx;
const tempDy = b1.dy;
b1.dx = b2.dx;
b1.dy = b2.dy;
b2.dx = tempDx;
b2.dy = tempDy;
// Slight speed increase
b1.dx *= SPEED_INCREASE;
b1.dy *= SPEED_INCREASE;
b2.dx *= SPEED_INCREASE;
b2.dy *= SPEED_INCREASE;
// Separate to avoid overlap sticking
const overlap = (b1.radius + b2.radius - distance) / 2;
const nx = dx / distance;
const ny = dy / distance;
b1.x -= nx * overlap;
b1.y -= ny * overlap;
b2.x += nx * overlap;
b2.y += ny * overlap;
}
}
}
// Remove balls going too fast
balls = balls.filter(b => b.getSpeed() <= MAX_SPEED);
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
balls.forEach(ball => {
ball.update();
ball.draw();
});
handleCollisions();
requestAnimationFrame(animate);
}
animate();
Top comments (0)