다중 볼 칠각형 물리 시뮬레이션
Wikiprompt, 무료 프롬프트 백과사전에서
다중 볼 칠각형 물리 시뮬레이션 I'll create a single-file HTML/CSS/JS simulation with 20 numbered, colored balls bouncing inside a rotating heptagon with gravity and wall collisions. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Bouncing Balls in Rotating Heptagon</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #1a1a2e; display: flex; justify-content: center; align-items: center; min-height: 100vh; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; overflow: hidden; } canvas { display: block; border-radius: 12px; box-shadow: 0 0 30px rgba(0, 0, 0, 0.5); background: #16213e; } .info { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); color: #e0e0e0; font-size: 14px; background: rgba(0, 0, 0, 0.6); padding: 8px 16px; border-radius: 20px; letter-spacing: 0.5px; backdrop-filter: blur(4px); } </style> </head> <body> <canvas id="simulationCanvas" width="800" height="600"></canvas> <div class="info">20 balls • rotating heptagon • gravity & collisions</div> <script> (function() { const canvas = document.getElementById('simulationCanvas'); const ctx = canvas.getContext('2d'); const W = canvas.width; const H = canvas.height; // Heptagon parameters const heptagonRadius = 260; const heptagonCenterX = W / 2; const heptagonCenterY = H / 2; const heptagonRotationSpeed = 0.002; // radians per frame let heptagonAngle = 0; // Gravity const gravity = 0.15; // Ball properties const ballCount = 20; const ballRadius = 12; const ballColors = [ '#e74c3c', '#e67e22', '#f1c40f', '#2ecc71', '#1abc9c', '#3498db', '#9b59b6', '#e84393', '#fd79a8', '#00b894', '#0984e3', '#6c5ce7', '#fdcb6e', '#e17055', '#00cec9', '#fab1a0', '#74b9ff', '#a29bfe', '#ff7675', '#55efc4' ]; // Ball class class Ball { constructor(id) { this.id = id; this.radius = ballRadius; this.x = heptagonCenterX + (Math.random() - 0.5) * 200; this.y = heptagonCenterY + (Math.random() - 0.5) * 200; this.vx = (Math.random() - 0.5) * 4; this.vy = (Math.random() - 0.5) * 4; this.color = ballColors[id % ballColors.length]; this.mass = 1; } update() { // Apply gravity this.vy += gravity; // Move this.x += this.vx; this.y += this.vy; // Collision with heptagon walls this.collideWithHeptagon(); } collideWithHeptagon() { // Get heptagon vertices in world coordinates const vertices = getHeptagonVertices(); // For each edge, check collision for (let i = 0; i < vertices.length; i++) { const v1 = vertices[i]; const v2 = vertices[(i + 1) % vertices.length]; // Find closest point on segment to ball center const closest = closestPointOnSegment(this.x, this.y, v1.x, v1.y, v2.x, v2.y); const dx = this.x - closest.x; const dy = this.y - closest.y; const distSq = dx * dx + dy * dy; if (distSq < this.radius * this.radius) { const dist = Math.sqrt(distSq); const nx = dx / dist; const ny = dy / dist; // Push ball out of wall this.x = closest.x + nx * this.radius; this.y = closest.y + ny * this.radius; // Reflect velocity const dot = this.vx * nx + this.vy * ny; if (dot < 0) { this.vx -= 2 * dot * nx; this.vy -= 2 * dot * ny; } // Small damping for stability this.vx *= 0.98; this.vy *= 0.98; } } } draw() { // Draw ball ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); ctx.fillStyle = this.color; ctx.fill(); ctx.strokeStyle = 'rgba(0,0,0,0.3)'; ctx.lineWidth = 1; ctx.stroke(); // Draw number ctx.fillStyle = '#ffffff'; ctx.font = 'bold 10px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(this.id + 1, this.x, this.y + 1); } } // Helper functions function getHeptagonVertices() { const vertices = []; const sides = 7; for (let i = 0; i < sides; i++) { const angle = heptagonAngle + (i * 2 * Math.PI) / sides; const x = heptagonCenterX + heptagonRadius * Math.cos(angle); const y = heptagonCenterY + heptagonRadius * Math.sin(angle); vertices.push({ x, y }); } return vertices; } function closestPointOnSegment(px, py, x1, y1, x2, y2) { const dx = x2 - x1; const dy = y2 - y1; const lenSq = dx * dx + dy * dy; if (lenSq === 0) return { x: x1, y: y1 }; let t = ((px - x1) * dx + (py - y1) * dy) / lenSq; t = Math.max(0, Math.min(1, t)); return { x: x1 + t * dx, y: y1 + t * dy }; } // Ball-to-ball collision function handleBallCollisions(balls) { for (let i = 0; i < balls.length; i++) { for (let j = i + 1; j < balls.length; j++) { const a = balls[i]; const b = balls[j]; const dx = b.x - a.x; const dy = b.y - a.y; const distSq = dx * dx + dy * dy; const minDist = a.radius + b.radius; if (distSq < minDist * minDist && distSq > 0.0001) { const dist = Math.sqrt(distSq); const nx = dx / dist; const ny = dy / dist; // Separate balls const overlap = minDist - dist; a.x -= nx * overlap / 2; a.y -= ny * overlap / 2; b.x += nx * overlap / 2; b.y += ny * overlap / 2; // Elastic collision (equal mass) const dvx = a.vx - b.vx; const dvy = a.vy - b.vy; const dot = dvx * nx + dvy * ny; if (dot > 0) { a.vx -= dot * nx; a.vy -= dot * ny; b.vx += dot * nx; b.vy += dot * ny; } } } } } // Initialize balls const balls = []; for (let i = 0; i < ballCount; i++) { balls.push(new Ball(i)); } // Draw heptagon function drawHeptagon() { const vertices = getHeptagonVertices(); ctx.beginPath(); ctx.moveTo(vertices[0].x, vertices[0].y); for (let i = 1; i < vertices.length; i++) { ctx.lineTo(vertices[i].x, vertices[i].y); } ctx.closePath(); // Fill with subtle gradient const gradient = ctx.createRadialGradient( heptagonCenterX, heptagonCenterY, 50, heptagonCenterX, heptagonCenterY, heptagonRadius ); gradient.addColorStop(0, 'rgba(255, 255, 255, 0.05)'); gradient.addColorStop(1, 'rgba(255, 255, 255, 0.02)'); ctx.fillStyle = gradient; ctx.fill(); // Stroke ctx.strokeStyle = '#4a69bd'; ctx.lineWidth = 3; ctx.stroke(); // Draw vertices as small dots ctx.fillStyle = '#4a69bd'; vertices.forEach(v => { ctx.beginPath(); ctx.arc(v.x, v.y, 4, 0, Math.PI * 2); ctx.fill(); }); } // Animation loop function animate() { // Clear canvas ctx.clearRect(0, 0, W, H); // Rotate heptagon heptagonAngle += heptagonRotationSpeed; // Update balls balls.forEach(ball => ball.update()); // Handle ball-to-ball collisions handleBallCollisions(balls); // Draw heptagon drawHeptagon(); // Draw balls balls.forEach(ball => ball.draw()); requestAnimationFrame(animate); } // Start animation animate(); })(); </script> </body> </html> ``` This simulation features: - 20 numbered balls with distinct colors - A rotating heptagon (7-sided polygon) that spins continuously - Gravity pulling balls downward - Collision detection with the heptagon's walls (reflection and position correction) - Ball-to-ball elastic collisions - Smooth animation using requestAnimationFrame - Visual styling with a dark theme and glowing heptagon edges The balls bounce realistically inside the rotating heptagon, creating an engaging physics simulation. The rotation adds dynamic complexity as the walls move, causing balls to interact with the changing geometry.
관련 미디어
프롬프트 내용저장
전체 프롬프트를 보려면 로그인하세요
Continue with:
By logging in, you agree to our Terms of Use and Privacy Policy
사용법
이 프롬프트는 coding와 함께 사용하도록 설계되었습니다. 위의 프롬프트 내용을 복사하여 원하는 AI 도구에 붙여넣으세요.
최상의 결과를 얻으려면 자리 표시자(대괄호 또는 대문자로 표시)를 특정 요구 사항으로 사용자 지정할 수 있습니다.
토론
댓글 0개