HTML5 Canvas 平台跳跃游戏

创建一个基于HTML5 Canvas的2D平台跳跃游戏,模拟OpenClaw的核心玩法。这个游戏将包含角色控制、平台跳跃、收集物品和敌人等元素。

设计思路

这个游戏将包含以下核心功能:

  • 使用键盘控制角色移动和跳跃
  • 物理引擎(重力、碰撞检测)
  • 收集物品系统
  • 简单的敌人AI
  • 关卡设计和进度

下面是完整的实现代码:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OpenClaw - 平台跳跃游戏</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Arial', sans-serif;
            background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            color: white;
            overflow: hidden;
        }

        .game-container {
            position: relative;
            width: 800px;
            height: 500px;
            background: rgba(0, 0, 0, 0.7);
            border-radius: 10px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
            overflow: hidden;
        }

        #gameCanvas {
            display: block;
            background: linear-gradient(to bottom, #87CEEB, #1E90FF);
            border-radius: 10px;
        }

        .game-ui {
            position: absolute;
            top: 10px;
            left: 10px;
            right: 10px;
            display: flex;
            justify-content: space-between;
            z-index: 10;
        }

        .score, .lives {
            background: rgba(0, 0, 0, 0.6);
            padding: 8px 15px;
            border-radius: 20px;
            font-weight: bold;
            font-size: 18px;
            display: flex;
            align-items: center;
        }

        .score span, .lives span {
            margin-left: 5px;
            color: #ffcc00;
        }

        .controls {
            position: absolute;
            bottom: 10px;
            left: 0;
            right: 0;
            text-align: center;
            background: rgba(0, 0, 0, 0.6);
            padding: 10px;
            border-radius: 5px;
            font-size: 14px;
        }

        .screen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: rgba(0, 0, 0, 0.8);
            z-index: 20;
            border-radius: 10px;
        }

        .screen h1 {
            font-size: 48px;
            margin-bottom: 20px;
            color: #ffcc00;
            text-shadow: 0 0 10px rgba(255, 204, 0, 0.5);
        }

        .screen p {
            font-size: 18px;
            margin: 10px 0;
            max-width: 80%;
            text-align: center;
            line-height: 1.5;
        }

        .btn {
            margin-top: 30px;
            padding: 12px 30px;
            background: linear-gradient(45deg, #ff8c00, #ffcc00);
            border: none;
            border-radius: 30px;
            color: #1a2a6c;
            font-size: 18px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            box-shadow: 0 5px 15px rgba(255, 140, 0, 0.4);
        }

        .btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 20px rgba(255, 140, 0, 0.6);
        }

        .btn:active {
            transform: translateY(1px);
        }

        .hidden {
            display: none;
        }

        .game-over {
            color: #ff4444;
        }

        .level-complete {
            color: #44ff44;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <canvas id="gameCanvas" width="800" height="500"></canvas>

        <div class="game-ui">
            <div class="score">分数: <span id="scoreValue">0</span></div>
            <div class="lives">生命: <span id="livesValue">3</span></div>
        </div>

        <div class="controls">
            使用方向键移动,空格键跳跃
        </div>

        <div id="startScreen" class="screen">
            <h1>OpenClaw</h1>
            <p>扮演勇敢的爪爪,穿越危险的平台,收集宝藏,击败敌人!</p>
            <p>使用方向键移动,空格键跳跃</p>
            <button class="btn" id="startBtn">开始游戏</button>
        </div>

        <div id="gameOverScreen" class="screen hidden">
            <h1 class="game-over">游戏结束</h1>
            <p>最终得分: <span id="finalScore">0</span></p>
            <button class="btn" id="restartBtn">重新开始</button>
        </div>

        <div id="levelCompleteScreen" class="screen hidden">
            <h1 class="level-complete">关卡完成!</h1>
            <p>得分: <span id="levelScore">0</span></p>
            <button class="btn" id="nextLevelBtn">下一关</button>
        </div>
    </div>

    <script>
        // 游戏主类
        class Game {
            constructor() {
                this.canvas = document.getElementById('gameCanvas');
                this.ctx = this.canvas.getContext('2d');
                this.width = this.canvas.width;
                this.height = this.canvas.height;

                // 游戏状态
                this.isRunning = false;
                this.level = 1;
                this.score = 0;
                this.lives = 3;

                // 游戏对象
                this.player = null;
                this.platforms = [];
                this.collectibles = [];
                this.enemies = [];

                // 键盘状态
                this.keys = {
                    left: false,
                    right: false,
                    up: false
                };

                // 绑定UI元素
                this.scoreValue = document.getElementById('scoreValue');
                this.livesValue = document.getElementById('livesValue');

                // 绑定屏幕
                this.startScreen = document.getElementById('startScreen');
                this.gameOverScreen = document.getElementById('gameOverScreen');
                this.levelCompleteScreen = document.getElementById('levelCompleteScreen');

                // 绑定按钮
                document.getElementById('startBtn').addEventListener('click', () => this.start());
                document.getElementById('restartBtn').addEventListener('click', () => this.restart());
                document.getElementById('nextLevelBtn').addEventListener('click', () => this.nextLevel());

                // 键盘事件
                window.addEventListener('keydown', (e) => this.handleKeyDown(e));
                window.addEventListener('keyup', (e) => this.handleKeyUp(e));

                // 初始化游戏
                this.init();
            }

            init() {
                this.showScreen(this.startScreen);
            }

            start() {
                this.hideAllScreens();
                this.isRunning = true;
                this.score = 0;
                this.lives = 3;
                this.level = 1;
                this.updateUI();
                this.loadLevel(this.level);
                this.gameLoop();
            }

            restart() {
                this.start();
            }

            nextLevel() {
                this.level++;
                this.hideAllScreens();
                this.isRunning = true;
                this.loadLevel(this.level);
                this.gameLoop();
            }

            loadLevel(level) {
                // 重置游戏对象
                this.platforms = [];
                this.collectibles = [];
                this.enemies = [];

                // 创建玩家
                this.player = new Player(100, 300, 40, 60);

                // 根据关卡生成不同的布局
                if (level === 1) {
                    // 平台
                    this.platforms.push(new Platform(0, 450, 800, 50)); // 地面
                    this.platforms.push(new Platform(200, 380, 150, 20));
                    this.platforms.push(new Platform(450, 320, 150, 20));
                    this.platforms.push(new Platform(100, 250, 120, 20));
                    this.platforms.push(new Platform(350, 180, 150, 20));
                    this.platforms.push(new Platform(600, 250, 120, 20));

                    // 收集品
                    this.collectibles.push(new Collectible(250, 340, 'coin'));
                    this.collectibles.push(new Collectible(500, 280, 'coin'));
                    this.collectibles.push(new Collectible(150, 210, 'gem'));
                    this.collectibles.push(new Collectible(400, 140, 'gem'));
                    this.collectibles.push(new Collectible(650, 210, 'coin'));

                    // 敌人
                    this.enemies.push(new Enemy(450, 300, 40, 40, 450, 550));
                } else if (level === 2) {
                    // 更复杂的关卡
                    this.platforms.push(new Platform(0, 450, 800, 50));
                    this.platforms.push(new Platform(150, 400, 100, 20));
                    this.platforms.push(new Platform(350, 350, 100, 20));
                    this.platforms.push(new Platform(550, 300, 100, 20));
                    this.platforms.push(new Platform(250, 250, 100, 20));
                    this.platforms.push(new Platform(450, 200, 100, 20));
                    this.platforms.push(new Platform(650, 150, 100, 20));

                    // 收集品
                    this.collectibles.push(new Collectible(200, 360, 'gem'));
                    this.collectibles.push(new Collectible(400, 310, 'coin'));
                    this.collectibles.push(new Collectible(600, 260, 'gem'));
                    this.collectibles.push(new Collectible(300, 210, 'coin'));
                    this.collectibles.push(new Collectible(500, 160, 'gem'));
                    this.collectibles.push(new Collectible(700, 110, 'coin'));

                    // 敌人
                    this.enemies.push(new Enemy(350, 330, 40, 40, 350, 450));
                    this.enemies.push(new Enemy(550, 280, 40, 40, 550, 650));
                }
            }

            updateUI() {
                this.scoreValue.textContent = this.score;
                this.livesValue.textContent = this.lives;
            }

            handleKeyDown(e) {
                if (e.code === 'ArrowLeft') this.keys.left = true;
                if (e.code === 'ArrowRight') this.keys.right = true;
                if (e.code === 'Space') this.keys.up = true;
            }

            handleKeyUp(e) {
                if (e.code === 'ArrowLeft') this.keys.left = false;
                if (e.code === 'ArrowRight') this.keys.right = false;
                if (e.code === 'Space') this.keys.up = false;
            }

            gameLoop() {
                if (!this.isRunning) return;

                // 更新游戏状态
                this.update();

                // 渲染游戏
                this.render();

                // 继续循环
                requestAnimationFrame(() => this.gameLoop());
            }

            update() {
                // 更新玩家
                this.player.update(this.keys, this.platforms);

                // 更新敌人
                this.enemies.forEach(enemy => enemy.update());

                // 检查收集品碰撞
                this.collectibles = this.collectibles.filter(collectible => {
                    if (this.checkCollision(this.player, collectible)) {
                        this.score += collectible.value;
                        this.updateUI();
                        return false; // 移除收集品
                    }
                    return true;
                });

                // 检查敌人碰撞
                this.enemies.forEach(enemy => {
                    if (this.checkCollision(this.player, enemy)) {
                        // 如果玩家从上方踩到敌人
                        if (this.player.velocityY > 0 &&
                            this.player.y + this.player.height < enemy.y + enemy.height / 2) {
                            this.score += 100;
                            this.updateUI();
                            // 移除敌人
                            this.enemies = this.enemies.filter(e => e !== enemy);
                        } else {
                            // 玩家受伤
                            this.lives--;
                            this.updateUI();
                            // 重置玩家位置
                            this.player.x = 100;
                            this.player.y = 300;
                            this.player.velocityY = 0;

                            if (this.lives <= 0) {
                                this.gameOver();
                            }
                        }
                    }
                });

                // 检查是否收集完所有物品
                if (this.collectibles.length === 0) {
                    this.levelComplete();
                }

                // 检查玩家是否掉出屏幕
                if (this.player.y > this.height) {
                    this.lives--;
                    this.updateUI();
                    this.player.x = 100;
                    this.player.y = 300;
                    this.player.velocityY = 0;

                    if (this.lives <= 0) {
                        this.gameOver();
                    }
                }
            }

            render() {
                // 清空画布
                this.ctx.clearRect(0, 0, this.width, this.height);

                // 绘制背景
                this.drawBackground();

                // 绘制平台
                this.platforms.forEach(platform => platform.draw(this.ctx));

                // 绘制收集品
                this.collectibles.forEach(collectible => collectible.draw(this.ctx));

                // 绘制敌人
                this.enemies.forEach(enemy => enemy.draw(this.ctx));

                // 绘制玩家
                this.player.draw(this.ctx);
            }

            drawBackground() {
                // 天空渐变
                const gradient = this.ctx.createLinearGradient(0, 0, 0, this.height);
                gradient.addColorStop(0, '#87CEEB');
                gradient.addColorStop(1, '#1E90FF');
                this.ctx.fillStyle = gradient;
                this.ctx.fillRect(0, 0, this.width, this.height);

                // 云朵
                this.ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
                this.drawCloud(100, 80, 30);
                this.drawCloud(300, 120, 40);
                this.drawCloud(600, 60, 35);
                this.drawCloud(500, 150, 25);
            }

            drawCloud(x, y, size) {
                this.ctx.beginPath();
                this.ctx.arc(x, y, size, 0, Math.PI * 2);
                this.ctx.arc(x + size, y, size * 0.8, 0, Math.PI * 2);
                this.ctx.arc(x - size, y, size * 0.8, 0, Math.PI * 2);
                this.ctx.arc(x + size * 0.5, y - size * 0.5, size * 0.7, 0, Math.PI * 2);
                this.ctx.arc(x - size * 0.5, y - size * 0.5, size * 0.7, 0, Math.PI * 2);
                this.ctx.fill();
            }

            checkCollision(rect1, rect2) {
                return rect1.x < rect2.x + rect2.width &&
                       rect1.x + rect1.width > rect2.x &&
                       rect1.y < rect2.y + rect2.height &&
                       rect1.y + rect1.height > rect2.y;
            }

            gameOver() {
                this.isRunning = false;
                document.getElementById('finalScore').textContent = this.score;
                this.showScreen(this.gameOverScreen);
            }

            levelComplete() {
                this.isRunning = false;
                document.getElementById('levelScore').textContent = this.score;
                this.showScreen(this.levelCompleteScreen);
            }

            showScreen(screen) {
                this.hideAllScreens();
                screen.classList.remove('hidden');
            }

            hideAllScreens() {
                this.startScreen.classList.add('hidden');
                this.gameOverScreen.classList.add('hidden');
                this.levelCompleteScreen.classList.add('hidden');
            }
        }

        // 玩家类
        class Player {
            constructor(x, y, width, height) {
                this.x = x;
                this.y = y;
                this.width = width;
                this.height = height;
                this.velocityX = 0;
                this.velocityY = 0;
                this.speed = 5;
                this.jumpPower = 12;
                this.gravity = 0.5;
                this.isGrounded = false;
            }

            update(keys, platforms) {
                // 水平移动
                this.velocityX = 0;
                if (keys.left) this.velocityX = -this.speed;
                if (keys.right) this.velocityX = this.speed;

                // 跳跃
                if (keys.up && this.isGrounded) {
                    this.velocityY = -this.jumpPower;
                    this.isGrounded = false;
                }

                // 应用重力
                this.velocityY += this.gravity;

                // 更新位置
                this.x += this.velocityX;
                this.y += this.velocityY;

                // 边界检查
                if (this.x < 0) this.x = 0;
                if (this.x + this.width > 800) this.x = 800 - this.width;

                // 平台碰撞检测
                this.isGrounded = false;
                for (let platform of platforms) {
                    if (this.checkPlatformCollision(platform)) {
                        // 从上方碰撞
                        if (this.velocityY > 0 &&
                            this.y + this.height > platform.y &&
                            this.y + this.height < platform.y + platform.height) {
                            this.y = platform.y - this.height;
                            this.velocityY = 0;
                            this.isGrounded = true;
                        }
                        // 从下方碰撞
                        else if (this.velocityY < 0 &&
                                 this.y < platform.y + platform.height &&
                                 this.y > platform.y) {
                            this.y = platform.y + platform.height;
                            this.velocityY = 0;
                        }
                        // 从左侧碰撞
                        else if (this.velocityX > 0 &&
                                 this.y + this.height > platform.y &&
                                 this.y < platform.y + platform.height) {
                            this.x = platform.x - this.width;
                        }
                        // 从右侧碰撞
                        else if (this.velocityX < 0 &&
                                 this.y + this.height > platform.y &&
                                 this.y < platform.y + platform.height) {
                            this.x = platform.x + platform.width;
                        }
                    }
                }
            }

            checkPlatformCollision(platform) {
                return this.x < platform.x + platform.width &&
                       this.x + this.width > platform.x &&
                       this.y < platform.y + platform.height &&
                       this.y + this.height > platform.y;
            }

            draw(ctx) {
                // 绘制身体
                ctx.fillStyle = '#FF6B6B';
                ctx.fillRect(this.x, this.y, this.width, this.height);

                // 绘制眼睛
                ctx.fillStyle = 'white';
                ctx.fillRect(this.x + 10, this.y + 15, 8, 8);
                ctx.fillRect(this.x + 22, this.y + 15, 8, 8);

                // 绘制瞳孔
                ctx.fillStyle = 'black';
                ctx.fillRect(this.x + 12, this.y + 17, 4, 4);
                ctx.fillRect(this.x + 24, this.y + 17, 4, 4);

                // 绘制嘴巴
                ctx.fillStyle = 'black';
                ctx.fillRect(this.x + 15, this.y + 35, 10, 3);

                // 绘制爪子
                ctx.fillStyle = '#333';
                ctx.fillRect(this.x + 5, this.y + 50, 8, 8);
                ctx.fillRect(this.x + 27, this.y + 50, 8, 8);
            }
        }

        // 平台类
        class Platform {
            constructor(x, y, width, height) {
                this.x = x;
                this.y = y;
                this.width = width;
                this.height = height;
            }

            draw(ctx) {
                // 绘制平台
                ctx.fillStyle = '#8B4513';
                ctx.fillRect(this.x, this.y, this.width, this.height);

                // 绘制平台边缘
                ctx.fillStyle = '#A0522D';
                ctx.fillRect(this.x, this.y, this.width, 5);

                // 绘制平台细节
                ctx.fillStyle = '#654321';
                for (let i = 10; i < this.width; i += 20) {
                    ctx.fillRect(this.x + i, this.y + 8, 5, 5);
                }
            }
        }

        // 收集品类
        class Collectible {
            constructor(x, y, type) {
                this.x = x;
                this.y = y;
                this.type = type;
                this.width = 20;
                this.height = 20;
                this.value = type === 'coin' ? 50 : 100;
                this.animationFrame = 0;
            }

            draw(ctx) {
                this.animationFrame += 0.1;
                const offset = Math.sin(this.animationFrame) * 3;

                if (this.type === 'coin') {
                    // 绘制金币
                    ctx.fillStyle = '#FFD700';
                    ctx.beginPath();
                    ctx.arc(this.x + 10, this.y + 10 + offset, 8, 0, Math.PI * 2);
                    ctx.fill();

                    ctx.fillStyle = '#FFA500';
                    ctx.beginPath();
                    ctx.arc(this.x + 10, this.y + 10 + offset, 5, 0, Math.PI * 2);
                    ctx.fill();
                } else {
                    // 绘制宝石
                    ctx.fillStyle = '#00FFFF';
                    ctx.beginPath();
                    ctx.moveTo(this.x + 10, this.y + offset);
                    ctx.lineTo(this.x + 20, this.y + 10 + offset);
                    ctx.lineTo(this.x + 10, this.y + 20 + offset);
                    ctx.lineTo(this.x, this.y + 10 + offset);
                    ctx.closePath();
                    ctx.fill();

                    ctx.fillStyle = '#008B8B';
                    ctx.beginPath();
                    ctx.moveTo(this.x + 10, this.y + 5 + offset);
                    ctx.lineTo(this.x + 15, this.y + 10 + offset);
                    ctx.lineTo(this.x + 10, this.y + 15 + offset);
                    ctx.lineTo(this.x + 5, this.y + 10 + offset);
                    ctx.closePath();
                    ctx.fill();
                }
            }
        }

        // 敌人类
        class Enemy {
            constructor(x, y, width, height, minX, maxX) {
                this.x = x;
                this.y = y;
                this.width = width;
                this.height = height;
                this.minX = minX;
                this.maxX = maxX;
                this.speed = 2;
                this.direction = 1; // 1表示向右,-1表示向左
            }

            update() {
                this.x += this.speed * this.direction;

                if (this.x >= this.maxX) {
                    this.direction = -1;
                } else if (this.x <= this.minX) {
                    this.direction = 1;
                }
            }

            draw(ctx) {
                // 绘制身体
                ctx.fillStyle = '#8B0000';
                ctx.fillRect(this.x, this.y, this.width, this.height);

                // 绘制眼睛
                ctx.fillStyle = 'yellow';
                ctx.fillRect(this.x + 10, this.y + 10, 8, 8);
                ctx.fillRect(this.x + 22, this.y + 10, 8, 8);

                // 绘制尖刺
                ctx.fillStyle = '#333';
                for (let i = 0; i < 4; i++) {
                    ctx.beginPath();
                    ctx.moveTo(this.x + i * 10, this.y);
                    ctx.lineTo(this.x + i * 10 + 5, this.y - 5);
                    ctx.lineTo(this.x + i * 10 + 10, this.y);
                    ctx.closePath();
                    ctx.fill();
                }
            }
        }

        // 启动游戏
        window.onload = () => {
            new Game();
        };
    </script>
</body>
</html>

游戏特点

    1. 完整的游戏流程
    • 开始界面
    • 游戏主界面
    • 关卡完成界面
    • 游戏结束界面
    1. 核心游戏机制
    • 平台跳跃物理系统
    • 碰撞检测(平台、收集品、敌人)
    • 敌人AI(简单巡逻)
    • 收集系统(金币和宝石)
    • 生命值和分数系统
    1. 视觉效果
    • 渐变背景和云朵
    • 角色和敌人动画
    • 收集品浮动效果
    • 简洁的UI界面
    1. 关卡设计
    • 两个不同难度的关卡
    • 每个关卡有不同的平台布局、收集品和敌人

游戏玩法

  1. 1.使用方向键(左右箭头)控制角色移动
  2. 2.使用空格键跳跃
  3. 3.收集所有物品(金币和宝石)完成关卡
  4. 4.避开敌人或从上方踩它们
  5. 5.小心不要掉出屏幕

您可以直接将此代码复制到HTML文件中,在浏览器中打开即可游玩。游戏完全自包含,不需要任何外部资源。

相关推荐
Qinana1 小时前
解构 LangChain Tool Calling:从 Schema 定义到 Agent 执行循环的深度解析
前端·javascript·node.js
YukiMori231 小时前
深入理解 JavaScript 执行机制:事件循环、执行栈、同步与异步彻底搞懂
前端·javascript·面试
卢叁2 小时前
Flutter之路由监听器
前端·flutter
三翼鸟数字化技术团队2 小时前
2025前端技术趋势:从智能到沉浸的新时代
前端·ai编程
恋猫de小郭2 小时前
Android 17 有什么需要适配的?2026 Android 禁止侧载又是什么?
android·前端·flutter
Never_Satisfied2 小时前
在HTML & CSS中,如何计算CSS特异性
前端·css·html
滕青山2 小时前
网页源代码查看在线工具 核心JS实现
前端·javascript·vue.js
www_stdio2 小时前
项目基础准备之Zustand:轻量级 React 状态管理的优雅之选
前端·react.js·typescript
躲在云朵里`2 小时前
同一账号在同一客户端类型只能登录一次
前端·spring·bootstrap