// Canvas setup const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Particle class class Particle { constructor(x, y, mass) { this.position = { x, y }; this.velocity = { x: 0, y: 0 }; this.acceleration = { x: 0, y: 0 }; this.mass = mass; } applyForce(force) { this.acceleration.x += force.x / this.mass; this.acceleration.y += force.y / this.mass; } update() { this.velocity.x += this.acceleration.x; this.velocity.y += this.acceleration.y; this.position.x += this.velocity.x; this.position.y += this.velocity.y; this.acceleration.x = 0; this.acceleration.y = 0; } draw() { ctx.beginPath(); ctx.arc(this.position.x, this.position.y, 5, 0, Math.PI * 2); ctx.fillStyle = 'black'; ctx.fill(); } } // Spring class class Spring { constructor(particleA, particleB, restLength, stiffness) { this.particleA = particleA; this.particleB = particleB; this.restLength = restLength; this.stiffness = stiffness; } update() { const dx = this.particleB.position.x - this.particleA.position.x; const dy = this.particleB.position.y - this.particleA.position.y; const distance = Math.sqrt(dx * dx + dy * dy); const forceMagnitude = (distance - this.restLength) * this.stiffness; const forceX = (dx / distance) * forceMagnitude; const forceY = (dy / distance) * forceMagnitude; this.particleA.applyForce({ x: -forceX, y: -forceY }); this.particleB.applyForce({ x: forceX, y: forceY }); } } // Create particles and springs const rows = 10; const cols = 10; const particleSpacing = 50; const particles = []; for (let i = 0; i < rows; i++) { for (let j = 0; j < cols; j++) { const x = j * particleSpacing; const y = i * particleSpacing; const particle = new Particle(x, y, 1); particles.push(particle); } } const springs = []; for (let i = 0; i < rows; i++) { for (let j = 0; j < cols; j++) { const currentParticle = particles[i * cols + j]; if (i > 0) { const topParticle = particles[(i - 1) * cols + j]; springs.push(new Spring(currentParticle, topParticle, particleSpacing, 0.1)); } if (j > 0) { const leftParticle = particles[i * cols + j - 1]; springs.push(new Spring(currentParticle, leftParticle, particleSpacing, 0.1)); } if (i < rows - 1 && j < cols - 1) { const diagonalParticle = particles[(i + 1) * cols + j + 1]; springs.push(new Spring(currentParticle, diagonalParticle, Math.sqrt(2) * particleSpacing, 0.05)); } } } // Simulation loop function simulate() { // Apply gravity for (const particle of particles) { particle.applyForce({ x: 0, y: 0.1 }); // Adjust gravity here } // Update springs for (const spring of springs) { spring.update(); } // Update particles for (const particle of particles) { particle.update(); } // Draw ctx.clearRect(0, 0, canvas.width, canvas.height); for (const particle of particles) { particle.draw(); } requestAnimationFrame(simulate); } simulate();