HTML跑酷

先看效果

再上代码

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>火柴人跑酷</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #87CEEB;
        }
        #gameCanvas {
            background: linear-gradient(to bottom, #87CEEB 0%, #87CEEB 50%, #228B22 50%, #228B22 100%);
        }
        #ui {
            position: fixed;
            top: 20px;
            left: 20px;
            font-family: Arial;
            font-size: 24px;
            color: white;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
        }
        #gameOver {
            display: none;
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0,0,0,0.8);
            color: white;
            padding: 20px;
            text-align: center;
            border-radius: 10px;
        }
    </style>
</head>
<body>
    <div id="ui">
        得分: <span id="score">0</span>
    </div>
    <div id="gameOver">
        <h2>游戏结束!</h2>
        <p>最终得分: <span id="finalScore">0</span></p>
        <button onclick="restartGame()">重玩</button>
    </div>
    <canvas id="gameCanvas"></canvas>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        let canvasWidth = window.innerWidth;
        let canvasHeight = window.innerHeight;
        canvas.width = canvasWidth;
        canvas.height = canvasHeight;

        // 游戏参数
        let gameSpeed = 10;
        let isJumping = false;
        let isGameOver = false;
        let score = 0;
        let gravity = 0.8;
        let jumpForce = -21;
        let groundLevel = canvasHeight * 0.8;

        // 火柴人参数
        let stickman = {
            x: 100,
            y: groundLevel - 60,
            width: 40,
            height: 80,
            velocityY: 0,
            isOnGround: true
        };

        // 障碍物数组
        let obstacles = [];
        let obstacleTypes = [
            { width: 30, height: 50 },
            { width: 50, height: 30 },
            { width: 40, height: 40 }
        ];

        // 游戏循环
        function gameLoop() {
            if (!isGameOver) {
                ctx.clearRect(0, 0, canvasWidth, canvasHeight);
                
                updateStickman();
                updateObstacles();
                checkCollisions();
                drawGround();
                drawStickman();
                drawObstacles();
                updateScore();
                
                requestAnimationFrame(gameLoop);
            }
        }

        function drawStickman() {
            // 绘制火柴人
            ctx.fillStyle = '#000';
            
            // 身体
            ctx.beginPath();
            ctx.moveTo(stickman.x + stickman.width/2, stickman.y);
            ctx.lineTo(stickman.x + stickman.width/2, stickman.y + stickman.height);
            ctx.stroke();
            
            // 头部
            ctx.beginPath();
            ctx.arc(stickman.x + stickman.width/2, stickman.y - 10, 15, 0, Math.PI * 2);
            ctx.stroke();
            
            // 腿
            ctx.beginPath();
            ctx.moveTo(stickman.x + stickman.width/2, stickman.y + stickman.height);
            ctx.lineTo(stickman.x, stickman.y + stickman.height + 30);
            ctx.moveTo(stickman.x + stickman.width/2, stickman.y + stickman.height);
            ctx.lineTo(stickman.x + stickman.width, stickman.y + stickman.height + 30);
            ctx.stroke();
        }

        function updateStickman() {
            // 重力应用
            if (!stickman.isOnGround) {
                stickman.velocityY += gravity;
                stickman.y += stickman.velocityY;
            }

            // 地面检测
            if (stickman.y + stickman.height > groundLevel) {
                stickman.y = groundLevel - stickman.height;
                stickman.velocityY = 0;
                stickman.isOnGround = true;
            }
        }

        function drawGround() {
            ctx.fillStyle = '#228B22';
            ctx.fillRect(0, groundLevel, canvasWidth, canvasHeight - groundLevel);
        }

        function generateObstacle() {
            if (Math.random() < 0.02) {
                let type = obstacleTypes[Math.floor(Math.random() * obstacleTypes.length)];
                obstacles.push({
                    x: canvasWidth,
                    y: groundLevel - type.height,
                    width: type.width,
                    height: type.height,
                    passed: false
                });
            }
        }

        function updateObstacles() {
            generateObstacle();
            
            for (let i = obstacles.length - 1; i >= 0; i--) {
                obstacles[i].x -= gameSpeed;
                
                if (obstacles[i].x + obstacles[i].width < 0) {
                    obstacles.splice(i, 1);
                }
            }
        }

        function drawObstacles() {
            ctx.fillStyle = '#8B4513';
            obstacles.forEach(obstacle => {
                ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
            });
        }

        function checkCollisions() {
            obstacles.forEach(obstacle => {
                if (
                    stickman.x < obstacle.x + obstacle.width &&
                    stickman.x + stickman.width > obstacle.x &&
                    stickman.y < obstacle.y + obstacle.height &&
                    stickman.y + stickman.height > obstacle.y
                ) {
                    gameOver();
                }

                if (!obstacle.passed && obstacle.x + obstacle.width < stickman.x) {
                    obstacle.passed = true;
                    score += 10;
                }
            });
        }

        function updateScore() {
            document.getElementById('score').textContent = score;
            gameSpeed += 0.001;
        }

        function gameOver() {
            isGameOver = true;
            document.getElementById('gameOver').style.display = 'block';
            document.getElementById('finalScore').textContent = score;
        }

        function restartGame() {
            isGameOver = false;
            score = 0;
            gameSpeed = 10;
            obstacles = [];
            stickman.y = groundLevel - 60;
            stickman.velocityY = 0;
            document.getElementById('gameOver').style.display = 'none';
            gameLoop();
        }

        // 事件监听
        document.addEventListener('keydown', (e) => {
            if ((e.code === 'Space' || e.code === 'ArrowUp') && stickman.isOnGround) {
                stickman.velocityY = jumpForce;
                stickman.isOnGround = false;
            }
        });

        // 窗口调整
        window.addEventListener('resize', () => {
            canvasWidth = window.innerWidth;
            canvasHeight = window.innerHeight;
            canvas.width = canvasWidth;
            canvas.height = canvasHeight;
            groundLevel = canvasHeight * 0.8;
        });

        // 启动游戏
        gameLoop();
    </script>
</body>
</html>
相关推荐
遗憾随她而去.15 分钟前
前端浏览器缓存深度解析:从原理到实战
前端
万行38 分钟前
企业级前后端认证方式
前端·windows
2501_948120151 小时前
基于Vue 3的可视化大屏系统设计
前端·javascript·vue.js
Jinuss1 小时前
源码分析之React中createFiberRoot方法创建Fiber根节点
前端·javascript·react.js
Jinuss2 小时前
源码分析之React中ReactDOMRoot实现
前端·javascript·react.js
web守墓人2 小时前
【前端】vue3的指令
前端
想起你的日子2 小时前
EFCore之Code First
前端·.netcore
框架图3 小时前
Html语法
前端·html
深耕AI3 小时前
【wordpress系列教程】07 网站迁移与备份
运维·服务器·前端·数据库