Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Particle Collider</title> | |
<style> | |
body { | |
margin: 0; | |
overflow: hidden; | |
background: #000; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
height: 100vh; | |
} | |
canvas { | |
border: 1px solid #333; | |
} | |
.controls { | |
position: fixed; | |
top: 10px; | |
left: 10px; | |
color: white; | |
} | |
button { | |
padding: 5px 10px; | |
margin: 5px; | |
cursor: pointer; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="controls"> | |
<button onclick="addParticles(10)">Add 10 Particles</button> | |
<button onclick="toggleGravity()">Toggle Gravity</button> | |
<button onclick="clearParticles()">Clear</button> | |
</div> | |
<canvas id="canvas"></canvas> | |
<script> | |
const canvas = document.getElementById('canvas'); | |
const ctx = canvas.getContext('2d'); | |
// Set canvas size | |
canvas.width = 800; | |
canvas.height = 600; | |
let particles = []; | |
let gravity = false; | |
class Particle { | |
constructor(x, y) { | |
this.x = x; | |
this.y = y; | |
this.radius = Math.random() * 10 + 5; | |
this.mass = this.radius; | |
this.vx = (Math.random() - 0.5) * 10; | |
this.vy = (Math.random() - 0.5) * 10; | |
this.color = `hsl(${Math.random() * 360}, 50%, 50%)`; | |
} | |
draw() { | |
ctx.beginPath(); | |
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); | |
ctx.fillStyle = this.color; | |
ctx.fill(); | |
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)'; | |
ctx.stroke(); | |
} | |
update() { | |
if (gravity) { | |
this.vy += 0.2; // Gravity effect | |
} | |
this.x += this.vx; | |
this.y += this.vy; | |
// Bounce off walls | |
if (this.x - this.radius < 0 || this.x + this.radius > canvas.width) { | |
this.vx *= -0.9; | |
this.x = Math.max(this.radius, Math.min(canvas.width - this.radius, this.x)); | |
} | |
if (this.y - this.radius < 0 || this.y + this.radius > canvas.height) { | |
this.vy *= -0.9; | |
this.y = Math.max(this.radius, Math.min(canvas.height - this.radius, this.y)); | |
} | |
} | |
} | |
function checkCollision(p1, p2) { | |
const dx = p2.x - p1.x; | |
const dy = p2.y - p1.y; | |
const distance = Math.sqrt(dx * dx + dy * dy); | |
if (distance < p1.radius + p2.radius) { | |
// Collision detected - Calculate collision response | |
const angle = Math.atan2(dy, dx); | |
const sin = Math.sin(angle); | |
const cos = Math.cos(angle); | |
// Rotate velocities | |
const vx1 = p1.vx * cos + p1.vy * sin; | |
const vy1 = p1.vy * cos - p1.vx * sin; | |
const vx2 = p2.vx * cos + p2.vy * sin; | |
const vy2 = p2.vy * cos - p2.vx * sin; | |
// Collision elastic equations | |
const m1 = p1.mass; | |
const m2 = p2.mass; | |
const u1 = vx1 * (m1 - m2) / (m1 + m2) + vx2 * 2 * m2 / (m1 + m2); | |
const u2 = vx2 * (m2 - m1) / (m1 + m2) + vx1 * 2 * m1 / (m1 + m2); | |
// Rotate velocities back | |
p1.vx = u1 * cos - vy1 * sin; | |
p1.vy = vy1 * cos + u1 * sin; | |
p2.vx = u2 * cos - vy2 * sin; | |
p2.vy = vy2 * cos + u2 * sin; | |
// Move particles apart to prevent sticking | |
const overlap = (p1.radius + p2.radius - distance) / 2; | |
p1.x -= overlap * cos; | |
p1.y -= overlap * sin; | |
p2.x += overlap * cos; | |
p2.y += overlap * sin; | |
} | |
} | |
function addParticles(count) { | |
for (let i = 0; i < count; i++) { | |
particles.push(new Particle( | |
Math.random() * canvas.width, | |
Math.random() * canvas.height | |
)); | |
} | |
} | |
function toggleGravity() { | |
gravity = !gravity; | |
} | |
function clearParticles() { | |
particles = []; | |
} | |
function animate() { | |
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
// Update and draw particles | |
particles.forEach(particle => { | |
particle.update(); | |
particle.draw(); | |
}); | |
// Check collisions | |
for (let i = 0; i < particles.length; i++) { | |
for (let j = i + 1; j < particles.length; j++) { | |
checkCollision(particles[i], particles[j]); | |
} | |
} | |
requestAnimationFrame(animate); | |
} | |
// Add initial particles and start animation | |
addParticles(20); | |
animate(); | |
// Mouse interaction | |
let isMouseDown = false; | |
canvas.addEventListener('mousedown', () => isMouseDown = true); | |
canvas.addEventListener('mouseup', () => isMouseDown = false); | |
canvas.addEventListener('mousemove', (e) => { | |
if (isMouseDown) { | |
const rect = canvas.getBoundingClientRect(); | |
const x = e.clientX - rect.left; | |
const y = e.clientY - rect.top; | |
particles.push(new Particle(x, y)); | |
} | |
}); | |
</script> | |
</body> | |
</html> |