HTML/JS/CSS 【跑酷游戏教程】含教程,源代码,解析!

HTML5 Canvas跑酷游戏开发教程

HTML5 Canvas 跑酷游戏实现

我将使用HTML5 Canvas和JavaScript创建一个类似Chrome恐龙游戏的跑酷游戏,无需任何外部库。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTML5 Canvas 跑酷游戏</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            overflow: hidden;
        }
        
        .game-container {
            position: relative;
            width: 800px;
            max-width: 95%;
            box-shadow: 0 0 30px rgba(0, 0, 0, 0.6);
            border-radius: 10px;
            overflow: hidden;
        }
        
        .game-header {
            background: linear-gradient(to right, #ff416c, #ff4b2b);
            color: white;
            padding: 15px 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 3px solid #ff8a00;
        }
        
        .game-title {
            font-size: 24px;
            font-weight: bold;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
        }
        
        .score-container {
            background: rgba(0, 0, 0, 0.3);
            padding: 8px 20px;
            border-radius: 30px;
            font-size: 20px;
            font-weight: bold;
        }
        
        .game-canvas-container {
            position: relative;
            background: #6b9ac4;
            height: 400px;
        }
        
        canvas {
            background: #87CEEB;
            display: block;
        }
        
        .ground {
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 30px;
            background: linear-gradient(to bottom, #8B4513, #5D2906);
            z-index: 10;
            border-top: 3px solid #704214;
        }
        
        .controls {
            background: rgba(0, 0, 0, 0.7);
            padding: 15px;
            color: white;
            text-align: center;
            font-size: 16px;
            border-top: 2px solid #ff8a00;
        }
        
        .game-over {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.85);
            display: none;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 100;
            color: white;
        }
        
        .game-over h2 {
            font-size: 48px;
            color: #ff416c;
            margin-bottom: 20px;
            text-shadow: 0 0 10px rgba(255, 65, 108, 0.7);
        }
        
        .final-score {
            font-size: 32px;
            margin-bottom: 30px;
        }
        
        .restart-btn {
            background: linear-gradient(to right, #00c9ff, #92fe9d);
            border: none;
            padding: 15px 40px;
            font-size: 20px;
            font-weight: bold;
            border-radius: 50px;
            cursor: pointer;
            transition: all 0.3s;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
        }
        
        .restart-btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
        }
        
        .game-info {
            position: absolute;
            top: 20px;
            left: 20px;
            background: rgba(0, 0, 0, 0.6);
            color: white;
            padding: 15px;
            border-radius: 10px;
            z-index: 50;
            max-width: 300px;
        }
        
        .character {
            position: absolute;
            bottom: 30px;
            left: 100px;
            z-index: 20;
        }
        
        .obstacle {
            position: absolute;
            bottom: 30px;
            z-index: 15;
        }
        
        .cloud {
            position: absolute;
            z-index: 5;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <div class="game-header">
            <div class="game-title">像素跑酷冒险</div>
            <div class="score-container">分数: <span id="score">0</span></div>
        </div>
        
        <div class="game-canvas-container">
            <canvas id="gameCanvas" width="800" height="400"></canvas>
            <div class="ground"></div>
            <div class="game-info">
                <h3>游戏说明</h3>
                <p>按空格键或上箭头跳跃,避开障碍物!</p>
                <p>游戏速度会随时间增加</p>
            </div>
            <div class="game-over" id="gameOver">
                <h2>游戏结束!</h2>
                <div class="final-score">最终分数: <span id="finalScore">0</span></div>
                <button class="restart-btn" onclick="restartGame()">重新开始</button>
            </div>
        </div>
        
        <div class="controls">
            控制: 空格键或上箭头键跳跃 | 游戏速度: <span id="speed">1.0</span>x
        </div>
    </div>

    <script>
        // 游戏主要变量
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const scoreElement = document.getElementById('score');
        const finalScoreElement = document.getElementById('finalScore');
        const gameOverScreen = document.getElementById('gameOver');
        const speedElement = document.getElementById('speed');
        
        // 游戏状态
        let gameRunning = true;
        let score = 0;
        let gameSpeed = 1.0;
        let speedIncreaseTimer = 0;
        
        // 玩家角色
        const player = {
            x: 100,
            y: canvas.height - 80,
            width: 40,
            height: 50,
            velocityY: 0,
            jumping: false,
            color: '#3498db',
            
            draw: function() {
                ctx.fillStyle = this.color;
                ctx.fillRect(this.x, this.y, this.width, this.height);
                
                // 绘制玩家细节
                ctx.fillStyle = '#2c3e50';
                ctx.fillRect(this.x + 10, this.y + 10, 8, 8); // 眼睛
                ctx.fillRect(this.x + 25, this.y + 10, 8, 8); // 眼睛
                
                ctx.fillStyle = '#e74c3c';
                ctx.fillRect(this.x + 15, this.y + 30, 10, 15); // 身体
                
                // 腿
                ctx.fillStyle = this.color;
                ctx.fillRect(this.x, this.y + 40, 10, 10);
                ctx.fillRect(this.x + 30, this.y + 40, 10, 10);
            },
            
            update: function() {
                // 重力
                this.velocityY += 0.6;
                this.y += this.velocityY;
                
                // 地面碰撞
                if (this.y > canvas.height - 80) {
                    this.y = canvas.height - 80;
                    this.velocityY = 0;
                    this.jumping = false;
                }
            },
            
            jump: function() {
                if (!this.jumping) {
                    this.velocityY = -15;
                    this.jumping = true;
                }
            }
        };
        
        // 障碍物
        let obstacles = [];
        
        function createObstacle() {
            const height = 30 + Math.random() * 30;
            const width = 20 + Math.random() * 20;
            const type = Math.random() > 0.7 ? 'tall' : 'wide';
            
            obstacles.push({
                x: canvas.width,
                y: canvas.height - 80 - (type === 'tall' ? height : 20),
                width: type === 'tall' ? width : 60,
                height: type === 'tall' ? height : 20,
                type: type,
                passed: false
            });
        }
        
        // 云朵
        let clouds = [];
        
        function createCloud() {
            clouds.push({
                x: canvas.width,
                y: 30 + Math.random() * 150,
                width: 60 + Math.random() * 40,
                speed: 0.5 + Math.random() * 1.0
            });
        }
        
        // 游戏循环
        function gameLoop() {
            // 清除画布
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            // 绘制背景
            drawBackground();
            
            // 更新和绘制云朵
            updateClouds();
            
            // 更新玩家
            player.update();
            player.draw();
            
            // 更新障碍物
            updateObstacles();
            
            // 更新分数
            updateScore();
            
            // 碰撞检测
            checkCollisions();
            
            // 随机生成障碍物
            if (Math.random() < 0.02 * gameSpeed) {
                createObstacle();
            }
            
            // 随机生成云朵
            if (Math.random() < 0.01) {
                createCloud();
            }
            
            // 增加游戏速度
            speedIncreaseTimer++;
            if (speedIncreaseTimer > 300) {
                gameSpeed += 0.1;
                speedIncreaseTimer = 0;
                speedElement.textContent = gameSpeed.toFixed(1);
            }
            
            // 继续游戏循环
            if (gameRunning) {
                requestAnimationFrame(gameLoop);
            }
        }
        
        function drawBackground() {
            // 天空
            const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
            gradient.addColorStop(0, "#87CEEB");
            gradient.addColorStop(1, "#E0F7FA");
            ctx.fillStyle = gradient;
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            // 远山
            ctx.fillStyle = "#5D8AA8";
            ctx.beginPath();
            ctx.moveTo(0, canvas.height - 100);
            for (let i = 0; i < canvas.width; i += 50) {
                const height = 50 + Math.sin(i * 0.05) * 20;
                ctx.lineTo(i, canvas.height - 100 - height);
            }
            ctx.lineTo(canvas.width, canvas.height - 100);
            ctx.lineTo(canvas.width, canvas.height);
            ctx.lineTo(0, canvas.height);
            ctx.closePath();
            ctx.fill();
        }
        
        function updateClouds() {
            for (let i = clouds.length - 1; i >= 0; i--) {
                const cloud = clouds[i];
                cloud.x -= cloud.speed * gameSpeed;
                
                // 绘制云朵
                ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
                ctx.beginPath();
                ctx.arc(cloud.x, cloud.y, cloud.width * 0.3, 0, Math.PI * 2);
                ctx.arc(cloud.x + cloud.width * 0.25, cloud.y - cloud.width * 0.1, cloud.width * 0.25, 0, Math.PI * 2);
                ctx.arc(cloud.x + cloud.width * 0.4, cloud.y, cloud.width * 0.3, 0, Math.PI * 2);
                ctx.arc(cloud.x - cloud.width * 0.2, cloud.y, cloud.width * 0.25, 0, Math.PI * 2);
                ctx.fill();
                
                // 移除屏幕外的云朵
                if (cloud.x + cloud.width < 0) {
                    clouds.splice(i, 1);
                }
            }
        }
        
        function updateObstacles() {
            for (let i = obstacles.length - 1; i >= 0; i--) {
                const obstacle = obstacles[i];
                
                // 移动障碍物
                obstacle.x -= 5 * gameSpeed;
                
                // 绘制障碍物
                ctx.fillStyle = obstacle.type === 'tall' ? "#e74c3c" : "#f39c12";
                ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
                
                // 添加障碍物细节
                ctx.fillStyle = "#c0392b";
                if (obstacle.type === 'tall') {
                    ctx.fillRect(obstacle.x + 5, obstacle.y + 5, obstacle.width - 10, 5);
                    ctx.fillRect(obstacle.x + 5, obstacle.y + 15, obstacle.width - 10, 5);
                } else {
                    for (let j = 0; j < 3; j++) {
                        ctx.fillRect(obstacle.x + 5 + j * 18, obstacle.y + 5, 10, 5);
                    }
                }
                
                // 计分
                if (!obstacle.passed && obstacle.x + obstacle.width < player.x) {
                    obstacle.passed = true;
                    score += 10;
                }
                
                // 移除屏幕外的障碍物
                if (obstacle.x + obstacle.width < 0) {
                    obstacles.splice(i, 1);
                }
            }
        }
        
        function updateScore() {
            score++;
            scoreElement.textContent = Math.floor(score / 5);
        }
        
        function checkCollisions() {
            for (let obstacle of obstacles) {
                if (
                    player.x < obstacle.x + obstacle.width &&
                    player.x + player.width > obstacle.x &&
                    player.y < obstacle.y + obstacle.height &&
                    player.y + player.height > obstacle.y
                ) {
                    endGame();
                    return;
                }
            }
        }
        
        function endGame() {
            gameRunning = false;
            finalScoreElement.textContent = Math.floor(score / 5);
            gameOverScreen.style.display = "flex";
        }
        
        function restartGame() {
            gameRunning = true;
            score = 0;
            gameSpeed = 1.0;
            speedIncreaseTimer = 0;
            obstacles = [];
            clouds = [];
            player.y = canvas.height - 80;
            player.velocityY = 0;
            player.jumping = false;
            gameOverScreen.style.display = "none";
            speedElement.textContent = gameSpeed.toFixed(1);
            gameLoop();
        }
        
        // 键盘控制
        document.addEventListener('keydown', function(e) {
            if ((e.code === 'Space' || e.key === 'ArrowUp') && gameRunning) {
                player.jump();
            }
        });
        
        // 触摸控制
        canvas.addEventListener('touchstart', function() {
            if (gameRunning) {
                player.jump();
            }
        });
        
        // 初始化游戏
        restartGame();
    </script>
</body>
</html>

游戏特点

这个HTML5 Canvas跑酷游戏具有以下特点:

  1. 响应式设计:适应不同屏幕尺寸
  2. 像素风格角色:玩家角色和障碍物采用简洁的像素风格
  3. 动态背景:渐变天空、山脉背景和移动的云朵
  4. 游戏机制
    • 按空格键或上箭头跳跃
    • 随机生成的障碍物(高障碍和宽障碍)
    • 随游戏进行速度逐渐增加
    • 碰撞检测
  5. 游戏界面
    • 实时分数显示
    • 游戏速度指示器
    • 游戏说明
    • 游戏结束界面(显示最终分数和重新开始按钮)

如何玩

  1. 打开页面后游戏自动开始
  2. 按空格键或上箭头键使角色跳跃
  3. 避开各种障碍物
  4. 游戏速度会随时间增加,增加挑战性
  5. 碰撞到障碍物后游戏结束
  6. 点击"重新开始"按钮可以再次游戏
    解析在代码中,请详细阅读!
    游戏已完全实现,只需复制整个代码到HTML文件中即可直接运行!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值