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 分钟前
LLM 驱动前端创新:AI 赋能营销合规实践
前端·程序员·llm
MariaH21 分钟前
深入了解vertical-align
前端
草巾冒小子35 分钟前
element-ui图片查看器
前端·vue.js·ui
光影少年1 小时前
vue3为什么不需要时间切片
前端·vue.js
Json_1 小时前
Vue 初识Hello word
前端·vue.js·深度学习
工藤孤独1 小时前
网页字体终极指南:从选择到优化加载体验
前端·css
一枚前端小姐姐1 小时前
git merge - 本地解决无权限dev分支的合并冲突
前端·git
Shi_haoliu1 小时前
各种网址整理-vue,前端,linux,ai前端开发,各种开发能用到的网址和一些有用的博客
linux·前端·javascript·vue.js·nginx·前端框架·pdf
喝奶茶不加糖1 小时前
什么是promise
前端·javascript