找回密码
 立即注册
搜索
热搜: 比赛 规则
查看: 21|回复: 0

编写一个html页面,一个小球在旋转的六边形内弹跳,小球要受到重力、摩擦力的影响

[复制链接]

43

主题

18

回帖

818

积分

超级版主

积分
818
发表于 昨天 11:26 | 显示全部楼层 |阅读模式
GLM-4-32B

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>六边形弹跳小球</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #f0f0f0;
            font-family: 'Arial', sans-serif;
            overflow: hidden;
        }
        
        .container {
            position: relative;
            width: 100%;
            max-width: 800px;
            text-align: center;
        }
        
        canvas {
            background-color: #fff;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            border-radius: 8px;
            margin-bottom: 20px;
        }
        
        .controls {
            margin-top: 20px;
            display: flex;
            justify-content: center;
            gap: 15px;
        }
        
        button {
            padding: 8px 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: background-color 0.3s;
        }
        
        button:hover {
            background-color: #45a049;
        }
        
        .slider-container {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        }
        
        .slider-container label {
            width: 120px;
            text-align: right;
        }
        
        input[type="range"] {
            width: 200px;
        }
        
        .value-display {
            width: 50px;
            text-align: left;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>六边形弹跳小球模拟</h1>
        <canvas id="canvas" width="600" height="600"></canvas>
        
        <div class="controls">
            <button id="resetBtn">重置</button>
            <button id="pauseBtn">暂停/继续</button>
        </div>
        
        <div class="slider-container">
            <label for="gravitySlider">重力大小:</label>
            <input type="range" id="gravitySlider" min="0" max="1" step="0.01" value="0.2">
            <span class="value-display" id="gravityValue">0.2</span>
        </div>
        
        <div class="slider-container">
            <label for="frictionSlider">摩擦系数:</label>
            <input type="range" id="frictionSlider" min="0" max="0.1" step="0.001" value="0.01">
            <span class="value-display" id="frictionValue">0.01</span>
        </div>
        
        <div class="slider-container">
            <label for="rotationSlider">旋转速度:</label>
            <input type="range" id="rotationSlider" min="0" max="0.05" step="0.001" value="0.01">
            <span class="value-display" id="rotationValue">0.01</span>
        </div>
    </div>

    <script>
        // 获取Canvas元素和上下文
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        
        // 获取控制元素
        const resetBtn = document.getElementById('resetBtn');
        const pauseBtn = document.getElementById('pauseBtn');
        const gravitySlider = document.getElementById('gravitySlider');
        const frictionSlider = document.getElementById('frictionSlider');
        const rotationSlider = document.getElementById('rotationSlider');
        const gravityValue = document.getElementById('gravityValue');
        const frictionValue = document.getElementById('frictionValue');
        const rotationValue = document.getElementById('rotationValue');
        
        // 初始化参数
        let isPaused = false;
        let gravity = parseFloat(gravitySlider.value);
        let friction = parseFloat(frictionSlider.value);
        let rotationSpeed = parseFloat(rotationSlider.value);
        let angle = 0;
        
        // 六边形参数
        const hexRadius = 200;
        const hexCenterX = canvas.width / 2;
        const hexCenterY = canvas.height / 2;
        
        // 小球参数
        let ball = {
            x: hexCenterX,
            y: hexCenterY,
            radius: 15,
            velocityX: 3,
            velocityY: 0,
            color: '#3498db'
        };
        
        // 计算六边形的顶点
        function calculateHexVertices() {
            const vertices = [];
            for (let i = 0; i < 6; i++) {
                const vertexAngle = angle + i * Math.PI / 3;
                const x = hexCenterX + hexRadius * Math.cos(vertexAngle);
                const y = hexCenterY + hexRadius * Math.sin(vertexAngle);
                vertices.push({ x, y });
            }
            return vertices;
        }
        
        // 绘制六边形
        function drawHexagon() {
            const vertices = calculateHexVertices();
            
            ctx.beginPath();
            ctx.moveTo(vertices[0].x, vertices[0].y);
            for (let i = 1; i < 6; i++) {
                ctx.lineTo(vertices.x, vertices.y);
            }
            ctx.closePath();
            ctx.strokeStyle = '#2c3e50';
            ctx.lineWidth = 3;
            ctx.stroke();
            
            // 填充六边形(半透明)
            ctx.fillStyle = 'rgba(236, 240, 241, 0.5)';
            ctx.fill();
            
            return vertices;
        }
        
        // 绘制小球
        function drawBall() {
            ctx.beginPath();
            ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
            ctx.fillStyle = ball.color;
            ctx.fill();
            ctx.strokeStyle = '#2980b9';
            ctx.lineWidth = 2;
            ctx.stroke();
        }
        
        // 检测小球与六边形的碰撞
        function checkCollision(vertices) {
            // 检查小球是否在六边形内部
            function isPointInHexagon(point, vertices) {
                let inside = false;
                for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++) {
                    const xi = vertices.x, yi = vertices.y;
                    const xj = vertices[j].x, yj = vertices[j].y;
                    
                    const intersect = ((yi > point.y) !== (yj > point.y))
                        && (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);
                    if (intersect) inside = !inside;
                }
                return inside;
            }
            
            // 如果小球在六边形外部,找到最近的边并反弹
            if (!isPointInHexagon(ball, vertices)) {
                // 找到最近的边
                let minDistance = Infinity;
                let closestEdge = null;
               
                for (let i = 0; i < 6; i++) {
                    const j = (i + 1) % 6;
                    const edge = {
                        start: vertices,
                        end: vertices[j]
                    };
                    
                    // 计算小球到边的距离
                    const distance = distanceToLine(ball, edge);
                    if (distance < minDistance) {
                        minDistance = distance;
                        closestEdge = edge;
                    }
                }
               
                if (closestEdge) {
                    // 计算边的法向量
                    const edgeVector = {
                        x: closestEdge.end.x - closestEdge.start.x,
                        y: closestEdge.end.y - closestEdge.start.y
                    };
                    
                    // 法向量(垂直于边)
                    const normal = {
                        x: -edgeVector.y,
                        y: edgeVector.x
                    };
                    
                    // 单位化法向量
                    const normalLength = Math.sqrt(normal.x * normal.x + normal.y * normal.y);
                    normal.x /= normalLength;
                    normal.y /= normalLength;
                    
                    // 确保法向量指向六边形内部
                    const centerToBall = {
                        x: ball.x - hexCenterX,
                        y: ball.y - hexCenterY
                    };
                    const dotProduct = normal.x * centerToBall.x + normal.y * centerToBall.y;
                    
                    if (dotProduct > 0) {
                        normal.x = -normal.x;
                        normal.y = -normal.y;
                    }
                    
                    // 计算反弹后的速度
                    const dot = ball.velocityX * normal.x + ball.velocityY * normal.y;
                    ball.velocityX = ball.velocityX - 2 * dot * normal.x;
                    ball.velocityY = ball.velocityY - 2 * dot * normal.y;
                    
                    // 应用摩擦力
                    ball.velocityX *= (1 - friction);
                    ball.velocityY *= (1 - friction);
                    
                    // 将小球推回六边形内部
                    const overlap = ball.radius - minDistance;
                    if (overlap > 0) {
                        ball.x += normal.x * overlap;
                        ball.y += normal.y * overlap;
                    }
                }
            }
        }
        
        // 计算点到线段的距离
        function distanceToLine(point, line) {
            const A = point.x - line.start.x;
            const B = point.y - line.start.y;
            const C = line.end.x - line.start.x;
            const D = line.end.y - line.start.y;
            
            const dot = A * C + B * D;
            const lenSq = C * C + D * D;
            let param = -1;
            
            if (lenSq !== 0) {
                param = dot / lenSq;
            }
            
            let xx, yy;
            
            if (param < 0) {
                xx = line.start.x;
                yy = line.start.y;
            } else if (param > 1) {
                xx = line.end.x;
                yy = line.end.y;
            } else {
                xx = line.start.x + param * C;
                yy = line.start.y + param * D;
            }
            
            const dx = point.x - xx;
            const dy = point.y - yy;
            
            return Math.sqrt(dx * dx + dy * dy);
        }
        
        // 更新小球位置
        function updateBall() {
            // 应用重力
            ball.velocityY += gravity;
            
            // 更新位置
            ball.x += ball.velocityX;
            ball.y += ball.velocityY;
            
            // 检测碰撞
            const vertices = calculateHexVertices();
            checkCollision(vertices);
        }
        
        // 动画循环
        function animate() {
            if (!isPaused) {
                // 清除画布
                ctx.clearRect(0, 0, canvas.width, canvas.height);
               
                // 更新旋转角度
                angle += rotationSpeed;
               
                // 绘制六边形
                const vertices = drawHexagon();
               
                // 更新和绘制小球
                updateBall();
                drawBall();
            }
            
            requestAnimationFrame(animate);
        }
        
        // 重置小球
        function resetBall() {
            ball.x = hexCenterX;
            ball.y = hexCenterY;
            ball.velocityX = 3;
            ball.velocityY = 0;
            angle = 0;
        }
        
        // 事件监听器
        resetBtn.addEventListener('click', resetBall);
        
        pauseBtn.addEventListener('click', function() {
            isPaused = !isPaused;
        });
        
        gravitySlider.addEventListener('input', function() {
            gravity = parseFloat(this.value);
            gravityValue.textContent = gravity.toFixed(2);
        });
        
        frictionSlider.addEventListener('input', function() {
            friction = parseFloat(this.value);
            frictionValue.textContent = friction.toFixed(3);
        });
        
        rotationSlider.addEventListener('input', function() {
            rotationSpeed = parseFloat(this.value);
            rotationValue.textContent = rotationSpeed.toFixed(3);
        });
        
        // 初始化显示值
        gravityValue.textContent = gravity.toFixed(2);
        frictionValue.textContent = friction.toFixed(3);
        rotationValue.textContent = rotationSpeed.toFixed(3);
        
        // 开始动画
        animate();
    </script>
</body>
</html>
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

网站使用中的任何问题都可以联系我。联系方式 邮箱:admin@archery.wang QQ:3030918630

更多主题

QQ|Archiver|手机版|小黑屋|AW射箭论坛/ArcheryWang ( 京ICP备2024088681号-1|京ICP备2024088681号-1 )

GMT+8, 2025-4-16 11:28

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.