Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!doctype html>
- <html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Bouncing Ball in Rotating Hexagon</title>
- <style>
- body {
- font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- min-height: 100vh;
- margin: 0;
- background-color: #f5f7fa;
- color: #333;
- }
- h1 {
- margin-bottom: 20px;
- color: #2c3e50;
- }
- canvas {
- background-color: #fff;
- border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
- margin-bottom: 20px;
- }
- .controls {
- display: flex;
- gap: 10px;
- margin-bottom: 20px;
- }
- button {
- padding: 10px 20px;
- background-color: #3498db;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- font-size: 16px;
- transition: background-color 0.3s;
- }
- button:hover {
- background-color: #2980b9;
- }
- .info {
- text-align: center;
- max-width: 600px;
- line-height: 1.6;
- color: #7f8c8d;
- }
- </style>
- </head>
- <body>
- <h1>Bouncing Ball in Rotating Hexagon</h1>
- <canvas id="canvas" width="500" height="500"></canvas>
- <div class="controls">
- <button id="resetBtn">Reset Simulation</button>
- <button id="pauseBtn">Pause/Resume</button>
- </div>
- <div class="info">
- Watch as the ball bounces around inside a rotating hexagon. The physics
- simulation includes gravity, bouncing effects, and collision detection
- with the hexagon's edges.
- </div>
- <script>
- // Canvas setup
- const canvas = document.getElementById("canvas");
- const ctx = canvas.getContext("2d");
- const width = canvas.width;
- const height = canvas.height;
- // Center of the canvas
- const centerX = width / 2;
- const centerY = height / 2;
- // Hexagon properties
- const hexRadius = 150;
- let hexRotation = 0;
- const hexRotationSpeed = 0.005; // radians per frame
- // Ball properties
- let ball = {
- x: centerX,
- y: centerY - 50,
- radius: 15,
- velocityX: 1,
- velocityY: 0,
- gravity: 0.2,
- friction: 0.99,
- bounce: 0.8,
- };
- // Animation control
- let animationId;
- let isPaused = false;
- // Hexagon vertices calculation
- function calculateHexVertices() {
- const vertices = [];
- for (let i = 0; i < 6; i++) {
- const angle = hexRotation + ((Math.PI * 2) / 6) * i;
- vertices.push({
- x: centerX + hexRadius * Math.cos(angle),
- y: centerY + hexRadius * Math.sin(angle),
- });
- }
- return vertices;
- }
- // Draw the hexagon
- function drawHexagon() {
- const vertices = calculateHexVertices();
- 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();
- ctx.strokeStyle = "#3498db";
- ctx.lineWidth = 3;
- ctx.stroke();
- // Fill with semi-transparent color
- ctx.fillStyle = "rgba(52, 152, 219, 0.1)";
- ctx.fill();
- }
- // Draw the ball
- function drawBall() {
- ctx.beginPath();
- ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
- ctx.fillStyle = "#e74c3c";
- ctx.fill();
- // Add a shine effect to the ball
- const gradient = ctx.createRadialGradient(
- ball.x - ball.radius / 3,
- ball.y - ball.radius / 3,
- 0,
- ball.x,
- ball.y,
- ball.radius,
- );
- gradient.addColorStop(0, "rgba(255, 255, 255, 0.8)");
- gradient.addColorStop(1, "rgba(231, 76, 60, 0.8)");
- ctx.beginPath();
- ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
- ctx.fillStyle = gradient;
- ctx.fill();
- }
- // Check collision between ball and hexagon edges
- function checkCollision() {
- const vertices = calculateHexVertices();
- // For each edge of the hexagon
- for (let i = 0; i < vertices.length; i++) {
- const p1 = vertices[i];
- const p2 = vertices[(i + 1) % vertices.length];
- // Calculate the closest point on the line segment to the ball center
- const edgeLength = Math.sqrt(
- Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2),
- );
- const dotProduct =
- ((ball.x - p1.x) * (p2.x - p1.x) +
- (ball.y - p1.y) * (p2.y - p1.y)) /
- (edgeLength * edgeLength);
- let closestX, closestY;
- if (dotProduct < 0) {
- // Closest to p1
- closestX = p1.x;
- closestY = p1.y;
- } else if (dotProduct > 1) {
- // Closest to p2
- closestX = p2.x;
- closestY = p2.y;
- } else {
- // Closest on the line segment
- closestX = p1.x + dotProduct * (p2.x - p1.x);
- closestY = p1.y + dotProduct * (p2.y - p1.y);
- }
- // Calculate distance from ball center to closest point
- const distance = Math.sqrt(
- Math.pow(ball.x - closestX, 2) + Math.pow(ball.y - closestY, 2),
- );
- // If distance is less than ball radius, collision occurred
- if (distance <= ball.radius) {
- // Calculate normal vector of the edge
- const edgeVectorX = p2.x - p1.x;
- const edgeVectorY = p2.y - p1.y;
- // Normalize the edge vector
- const edgeLengthNorm = Math.sqrt(
- edgeVectorX * edgeVectorX + edgeVectorY * edgeVectorY,
- );
- const normalX = -edgeVectorY / edgeLengthNorm; // Perpendicular to edge
- const normalY = edgeVectorX / edgeLengthNorm;
- // Calculate dot product of velocity and normal
- const dotVelocityNormal =
- ball.velocityX * normalX + ball.velocityY * normalY;
- // Apply bounce effect with the normal
- ball.velocityX -= (1 + ball.bounce) * dotVelocityNormal * normalX;
- ball.velocityY -= (1 + ball.bounce) * dotVelocityNormal * normalY;
- // Move ball outside of collision
- const overlap = ball.radius - distance;
- ball.x += overlap * normalX;
- ball.y += overlap * normalY;
- }
- }
- }
- // Update ball position and handle physics
- function updateBall() {
- // Apply gravity
- ball.velocityY += ball.gravity;
- // Apply friction
- ball.velocityX *= ball.friction;
- ball.velocityY *= ball.friction;
- // Update position
- ball.x += ball.velocityX;
- ball.y += ball.velocityY;
- // Check collision with hexagon edges
- checkCollision();
- }
- // Main animation loop
- function animate() {
- ctx.clearRect(0, 0, width, height);
- // Rotate the hexagon
- hexRotation += hexRotationSpeed;
- // Draw and update elements
- drawHexagon();
- updateBall();
- drawBall();
- // Continue animation
- if (!isPaused) {
- animationId = requestAnimationFrame(animate);
- }
- }
- // Reset the simulation
- function resetSimulation() {
- ball = {
- x: centerX,
- y: centerY - 50,
- radius: 15,
- velocityX: Math.random() * 4 - 2, // Random initial X velocity
- velocityY: 0,
- gravity: 0.2,
- friction: 0.99,
- bounce: 0.8,
- };
- hexRotation = 0;
- if (!animationId && !isPaused) {
- animate();
- }
- }
- // Toggle pause/resume
- function togglePause() {
- isPaused = !isPaused;
- if (isPaused) {
- cancelAnimationFrame(animationId);
- } else {
- animate();
- }
- }
- // Event listeners
- document
- .getElementById("resetBtn")
- .addEventListener("click", resetSimulation);
- document
- .getElementById("pauseBtn")
- .addEventListener("click", togglePause);
- // Start the animation
- resetSimulation();
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement