当前位置: 首页 > news >正文

11.14 脚本网页 迷宫逃离

  一  博主今天摸鱼,闲着没事儿写了一个迷宫逃离的游戏。

 二   代码不做解释自己,可问AI

  代码开源,后续优化自己随意

 <!DOCTYPE html>

<html lang="zh-CN">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>迷宫逃脱·最终版</title>

    <style>

        * {

            margin: 0;

            padding: 0;

            box-sizing: border-box;

            -webkit-tap-highlight-color: transparent;

            -webkit-touch-callout: none;

            -webkit-user-select: none;

            user-select: none;

        }

        

        body {

            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

            background: linear-gradient(135deg, #0d1b2a, #1f3a5f, #00ffcc);

            color: white;

            height: 100vh;

            overflow: hidden;

            display: flex;

            flex-direction: column;

            align-items: center;

            justify-content: center;

            text-align: center;

            padding: 10px;

            transition: background 0.5s ease;

        }

        

        #game-container {

            position: relative;

            width: 100%;

            height: 100%;

            max-width: 400px;

            max-height: 700px;

            display: flex;

            flex-direction: column;

        }

        

        #start-screen, #game-screen, #end-screen {

            width: 100%;

            height: 100%;

            display: flex;

            flex-direction: column;

            align-items: center;

            justify-content: center;

            padding: 20px;

            transition: opacity 0.3s;

        }

        

        #game-screen {

            display: none;

        }

        

        #end-screen {

            display: none;

        }

        

        h1 {

            font-size: 2.2rem;

            margin-bottom: 15px;

            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);

            color: #FFD700;

        }

        

        h2 {

            font-size: 1.6rem;

            margin-bottom: 10px;

            color: #4CAF50;

        }

        

        p {

            font-size: 1rem;

            margin-bottom: 15px;

            line-height: 1.4;

        }

        

        .difficulty-option {

            width: 90%;

            padding: 12px;

            margin: 8px 0;

            background: rgba(255, 255, 255, 0.15);

            border: 2px solid;

            border-radius: 12px;

            font-size: 1.1rem;

            color: white;

            cursor: pointer;

            transition: all 0.2s;

        }

        

        .difficulty-option:active {

            transform: scale(0.98);

        }

        

        .difficulty-option.easy {

            border-color: #4CAF50;

            background: rgba(76, 175, 80, 0.2);

        }

        

        .difficulty-option.normal {

            border-color: #FF9800;

            background: rgba(255, 152, 0, 0.2);

        }

        

        .difficulty-option.hard {

            border-color: #F44336;

            background: rgba(244, 67, 54, 0.2);

        }

        

        #game-area {

            position: relative;

            width: 100%;

            flex: 1;

            background: #0d1b2a;

            border-radius: 8px;

            overflow: hidden;

            margin-bottom: 10px;

        }

        

        #game-canvas {

            display: block;

            width: 100%;

            height: 100%;

        }

        

        #ui {

            display: flex;

            justify-content: space-around;

            width: 100%;

            background: rgba(0, 0, 0, 0.6);

            padding: 8px;

            border-radius: 8px;

            font-size: 1rem;

            margin-bottom: 10px;

        }

        

        #controls {

            display: flex;

            justify-content: space-between;

            width: 100%;

            height: 120px;

        }

        

        .d-pad {

            display: grid;

            grid-template-columns: repeat(3, 1fr);

            grid-template-rows: repeat(3, 1fr);

            gap: 5px;

            width: 120px;

            height: 120px;

        }

        

        .control-btn {

            background: rgba(255, 255, 255, 0.2);

            border: 2px solid rgba(255, 255, 255, 0.4);

            border-radius: 8px;

            color: white;

            display: flex;

            align-items: center;

            justify-content: center;

            font-size: 1.5rem;

            cursor: pointer;

            transition: all 0.1s;

        }

        

        .control-btn:active {

            background: rgba(255, 255, 255, 0.4);

            transform: scale(0.95);

        }

        

        .control-btn.center {

            grid-column: 2;

            grid-row: 2;

            visibility: hidden;

        }

        

        #action-buttons {

            display: flex;

            flex-direction: column;

            justify-content: space-between;

            width: 120px;

        }

        

        .action-btn {

            height: 55px;

            background: rgba(76, 175, 80, 0.3);

            border: 2px solid #4CAF50;

            border-radius: 8px;

            color: white;

            font-size: 1rem;

            display: flex;

            align-items: center;

            justify-content: center;

            cursor: pointer;

        }

        

        .action-btn:active {

            background: rgba(76, 175, 80, 0.5);

        }

        

        button {

            padding: 10px 20px;

            margin: 8px;

            background: #4CAF50;

            border: none;

            border-radius: 20px;

            font-size: 1rem;

            color: white;

            cursor: pointer;

            transition: all 0.2s;

        }

        

        button:active {

            transform: scale(0.95);

        }

        

        #mute-btn {

            position: absolute;

            top: 10px;

            right: 10px;

            width: 36px;

            height: 36px;

            background: rgba(255, 255, 255, 0.2);

            border-radius: 50%;

            display: flex;

            align-items: center;

            justify-content: center;

            cursor: pointer;

            font-size: 1rem;

        }

        

        #theme-btn {

            position: absolute;

            top: 10px;

            left: 10px;

            width: 36px;

            height: 36px;

            background: rgba(255, 255, 255, 0.2);

            border-radius: 50%;

            display: flex;

            align-items: center;

            justify-content: center;

            cursor: pointer;

            font-size: 0.8rem;

        }

        

        .instructions {

            font-size: 0.9rem;

            color: #ccc;

            margin-top: 10px;

        }

        

        .score-display {

            position: absolute;

            top: 60px;

            right: 10px;

            background: rgba(0, 0, 0, 0.6);

            padding: 5px 10px;

            border-radius: 10px;

            font-size: 0.9rem;

        }

    </style>

</head>

<body>

    <div id="game-container">

        <div id="start-screen">

            <h1>迷宫逃脱</h1>

            <p>收集所有钥匙,避开敌人,找到出口!</p>

            <p>当前积分: <span id="total-score">0</span></p>

            <p>选择难度开始游戏:</p>

            <p style="color:#FFD700; font-size:0.9rem;">⚠️ 必须先收集 5 把钥匙,否则出口无效!</p>

            <div class="difficulty-option easy" data-difficulty="easy">简单模式 - 敌人速度慢,不会穿墙</div>

            <div class="difficulty-option normal" data-difficulty="normal">普通模式 - 敌人速度中等</div>

            <div class="difficulty-option hard" data-difficulty="hard">困难模式 - 敌人速度快</div>

            <p class="instructions">使用方向键控制角色移动</p>

        </div>

        

        <div id="game-screen">

            <div id="game-area">

                <canvas id="game-canvas"></canvas>

            </div>

            <div id="ui">

                <div>生命: <span id="hp">3</span></div>

                <div>钥匙: <span id="keys">0</span>/5</div>

                <div>时间: <span id="time">60</span>s</div>

            </div>

            <p style="color:#FFD700; font-size:0.9rem;">⚠️ 必须先收集 5 把钥匙,否则出口无效!</p>

            <div id="controls">

                <div class="d-pad">

                    <div class="control-btn"></div>

                    <div class="control-btn up" id="up-btn">↑</div>

                    <div class="control-btn"></div>

                    <div class="control-btn left" id="left-btn">←</div>

                    <div class="control-btn center"></div>

                    <div class="control-btn right" id="right-btn">→</div>

                    <div class="control-btn"></div>

                    <div class="control-btn down" id="down-btn">↓</div>

                    <div class="control-btn"></div>

                </div>

                <div id="action-buttons">

                    <div class="action-btn" id="pause-btn">暂停</div>

                    <div class="action-btn" id="restart-game-btn">重来</div>

                </div>

            </div>

        </div>

        

        <div id="end-screen">

            <h2 id="result-message"></h2>

            <p id="result-details"></p>

            <p>本局得分: <span id="round-score">0</span></p>

            <p>总积分: <span id="total-score-end">0</span></p>

            <button id="restart-btn">再玩一次</button>

            <button id="menu-btn">返回主菜单</button>

        </div>

        

        <div id="mute-btn">🔊</div>

        <div id="theme-btn">🎨</div>

        <div class="score-display">积分: <span id="score-display">0</span></div>

    </div>

 

    <script>

        // 游戏配置

        const CONFIG = {

            canvasWidth: 360,

            canvasHeight: 480,

            keysRequired: 5,

            initialLives: 3,

            gameTime: 60

        };

        

        // 难度设置

        const DIFFICULTY = {

            easy: { enemySpeed: 0.8, playerSpeed: 3.5, scoreMultiplier: 1 },

            normal: { enemySpeed: 1.5, playerSpeed: 3.5, scoreMultiplier: 2 },

            hard: { enemySpeed: 2.5, playerSpeed: 3.5, scoreMultiplier: 3 }

        };

        

        // 背景主题颜色数组

        const THEMES = [

            'linear-gradient(135deg, #0f2027, #203a43, #2c5364)',

            'linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d)',

            'linear-gradient(135deg, #3a1c71, #d76d77, #ffaf7b)',

            'linear-gradient(135deg, #2193b0, #6dd5ed)',

            'linear-gradient(135deg, #834d9b, #d04ed6)',

            'linear-gradient(135deg, #0f0c29, #302b63, #24243e)',

            'linear-gradient(135deg, #c31432, #240b36)',

            'linear-gradient(135deg, #7b4397, #dc2430)',

            'linear-gradient(135deg, #00b4db, #0083b0)',

            'linear-gradient(135deg, #fd746c, #ff9068)',

            'linear-gradient(135deg, #556270, #ff6b6b)',

            'linear-gradient(135deg, #4ca1af, #2c3e50)',

            'linear-gradient(135deg, #ff9a9e, #fecfef)',

            'linear-gradient(135deg, #a8ff78, #78ffd6)',

            'linear-gradient(135deg, #f46b45, #eea849)'

        ];

        

        // 游戏状态

        let gameState = {

            currentScreen: 'start',

            difficulty: 'normal',

            player: null,

            enemies: [],

            keys: [],

            walls: [],

            particles: [],

            lives: CONFIG.initialLives,

            keysCollected: 0,

            timeLeft: CONFIG.gameTime,

            invincible: 0,

            gameOver: false,

            paused: false,

            maze: null,

            keysPressed: {},

            totalScore: 0,

            currentRoundScore: 0,

            currentTheme: 0

        };

        

        // DOM元素

        const startScreen = document.getElementById('start-screen');

        const gameScreen = document.getElementById('game-screen');

        const endScreen = document.getElementById('end-screen');

        const gameCanvas = document.getElementById('game-canvas');

        const ctx = gameCanvas.getContext('2d');

        const hpElement = document.getElementById('hp');

        const keysElement = document.getElementById('keys');

        const timeElement = document.getElementById('time');

        const resultMessage = document.getElementById('result-message');

        const resultDetails = document.getElementById('result-details');

        const restartBtn = document.getElementById('restart-btn');

        const menuBtn = document.getElementById('menu-btn');

        const muteBtn = document.getElementById('mute-btn');

        const themeBtn = document.getElementById('theme-btn');

        const pauseBtn = document.getElementById('pause-btn');

        const restartGameBtn = document.getElementById('restart-game-btn');

        const scoreDisplay = document.getElementById('score-display');

        const totalScoreElement = document.getElementById('total-score');

        const totalScoreEndElement = document.getElementById('total-score-end');

        const roundScoreElement = document.getElementById('round-score');

        

        // 音频上下文

        let audioContext;

        let muted = false;

        

        // 初始化游戏

        function initGame() {

            // 设置画布尺寸

            gameCanvas.width = CONFIG.canvasWidth;

            gameCanvas.height = CONFIG.canvasHeight;

            

            // 生成迷宫 - 确保出口连通

            const mazeWidth = 9;

            const mazeHeight = 12;

            const cellSize = Math.min(CONFIG.canvasWidth / mazeWidth, CONFIG.canvasHeight / mazeHeight);

            

            gameState.maze = generateMazeWithConnectedExit(mazeWidth, mazeHeight);

            gameState.walls = createWallsFromMaze(gameState.maze, cellSize);

            

            // 创建玩家

            gameState.player = {

                x: cellSize * 1.5,

                y: cellSize + cellSize/2,

                radius: 8,

                dx: 0,

                dy: 0

            };

            

            // 创建敌人

            gameState.enemies = [];

            const enemyCount = gameState.difficulty === 'easy' ? 2 : 

                              gameState.difficulty === 'normal' ? 3 : 4;

            

            for (let i = 0; i < enemyCount; i++) {

                let enemyX, enemyY;

                let attempts = 0;

                

                do {

                    enemyX = Math.floor(Math.random() * (mazeWidth-2)) + 1;

                    enemyY = Math.floor(Math.random() * (mazeHeight-2)) + 1;

                    attempts++;

                    

                    if (attempts > 100) break;

                } while (gameState.maze[enemyY][enemyX] !== 0 || 

                        (enemyX <= 2 && enemyY <= 2) ||

                        (enemyX === mazeWidth-2 && enemyY === mazeHeight-2));

                

                if (attempts <= 100) {

                    gameState.enemies.push({

                        x: enemyX * cellSize + cellSize/2,

                        y: enemyY * cellSize + cellSize/2,

                        radius: 10

                    });

                }

            }

            

            // 创建钥匙

            gameState.keys = [];

            for (let i = 0; i < CONFIG.keysRequired; i++) {

                let keyX, keyY;

                do {

                    keyX = Math.floor(Math.random() * (mazeWidth-2)) + 1;

                    keyY = Math.floor(Math.random() * (mazeHeight-2)) + 1;

                } while (gameState.maze[keyY][keyX] !== 0 || 

                        (keyX <= 2 && keyY <= 2) ||

                        (keyX === mazeWidth-2 && keyY === mazeHeight-2));

                

                gameState.keys.push({

                    x: keyX * cellSize + cellSize/2,

                    y: keyY * cellSize + cellSize/2,

                    radius: 6,

                    collected: false

                });

            }

            

            // 重置游戏状态

            gameState.lives = CONFIG.initialLives;

            gameState.keysCollected = 0;

            gameState.timeLeft = CONFIG.gameTime;

            gameState.invincible = 0;

            gameState.gameOver = false;

            gameState.paused = false;

            gameState.particles = [];

            gameState.keysPressed = {};

            gameState.currentRoundScore = 0;

            

            // 更新UI

            hpElement.textContent = gameState.lives;

            keysElement.textContent = gameState.keysCollected;

            timeElement.textContent = gameState.timeLeft;

            pauseBtn.textContent = '暂停';

            scoreDisplay.textContent = gameState.totalScore;

            totalScoreElement.textContent = gameState.totalScore;

        }

        

        // 生成迷宫,确保出口连通

        function generateMazeWithConnectedExit(width, height) {

            // 创建网格,初始全部为墙

            const grid = Array(height).fill().map(() => Array(width).fill(1));

            

            // 使用深度优先搜索生成迷宫

            function carve(x, y) {

                grid[y][x] = 0;

                

                const directions = [

                    [0, -2],

                    [2, 0],

                    [0, 2],

                    [-2, 0]

                ];

                

                for (let i = directions.length - 1; i > 0; i--) {

                    const j = Math.floor(Math.random() * (i + 1));

                    [directions[i], directions[j]] = [directions[j], directions[i]];

                }

                

                for (const [dx, dy] of directions) {

                    const nx = x + dx, ny = y + dy;

                    

                    if (nx > 0 && nx < width - 1 && ny > 0 && ny < height - 1 && grid[ny][nx] === 1) {

                        grid[y + dy/2][x + dx/2] = 0;

                        carve(nx, ny);

                    }

                }

            }

            

            // 从起点开始生成

            carve(1, 1);

            

            // 确保出口连通 - 这是关键修复

            grid[height-2][width-2] = 0;

            

            // 确保有一条路径连接到出口

            if (grid[height-3][width-2] === 1) {

                grid[height-3][width-2] = 0;

            }

            if (grid[height-2][width-3] === 1) {

                grid[height-2][width-3] = 0;

            }

            

            // 创建第二条路径

            createSecondPath(grid, width, height);

            

    // ✅ 清空出口周围 3×3 区域,确保出口是开放的

const exitX = width - 2;

const exitY = height - 2;

for (let dy = -1; dy <= 1; dy++) {

    for (let dx = -1; dx <= 1; dx++) {

        const nx = exitX + dx;

        const ny = exitY + dy;

        if (nx >= 0 && nx < width && ny >= 0 && ny < height) {

            grid[ny][nx] = 0;

        }

    }

}

 

// ✅ 再打通一条从起点到出口的路径(避免被墙挡住)

let cx = 1, cy = 1;

while (cx !== exitX || cy !== exitY) {

    if (cx < exitX) {

        grid[cy][cx + 1] = 0;

        cx++;

    } else if (cy < exitY) {

        grid[cy + 1][cx] = 0;

        cy++;

    }

}

 

 

            return grid;

        }

        

        // 创建第二条路径

        function createSecondPath(grid, width, height) {

            // 从右下角向左上角创建一条路径

            let x = width-2, y = height-2;

            

            while (x > 1 || y > 1) {

                if (x > 1 && (Math.random() < 0.5 || y === 1)) {

                    grid[y][x-1] = 0;

                    x--;

                } else if (y > 1) {

                    grid[y-1][x] = 0;

                    y--;

                }

            }

        }

        

        // 从迷宫网格创建墙壁

        function createWallsFromMaze(maze, cellSize) {

            const walls = [];

            const height = maze.length;

            const width = maze[0].length;

            

            for (let y = 0; y < height; y++) {

                for (let x = 0; x < width; x++) {

                    if (maze[y][x] === 1) {

                        walls.push({

                            x: x * cellSize,

                            y: y * cellSize,

                            width: cellSize,

                            height: cellSize

                        });

                    }

                }

            }

            

            return walls;

        }

        

        // 游戏主循环

        function gameLoop() {

            if (gameState.gameOver || gameState.paused) {

                requestAnimationFrame(gameLoop);

                return;

            }

            

            update();

            render();

            requestAnimationFrame(gameLoop);

        }

        

        // 更新游戏状态

        function update() {

            const player = gameState.player;

            const difficultySettings = DIFFICULTY[gameState.difficulty];

            

            // 更新玩家位置

            player.dx = 0;

            player.dy = 0;

            

            if (gameState.keysPressed['ArrowUp'] || gameState.keysPressed['up']) {

                player.dy = -difficultySettings.playerSpeed;

            }

            if (gameState.keysPressed['ArrowDown'] || gameState.keysPressed['down']) {

                player.dy = difficultySettings.playerSpeed;

            }

            if (gameState.keysPressed['ArrowLeft'] || gameState.keysPressed['left']) {

                player.dx = -difficultySettings.playerSpeed;

            }

            if (gameState.keysPressed['ArrowRight'] || gameState.keysPressed['right']) {

                player.dx = difficultySettings.playerSpeed;

            }

            

            if (player.dx !== 0 && player.dy !== 0) {

                player.dx *= 0.707;

                player.dy *= 0.707;

            }

            

            const oldX = player.x;

            const oldY = player.y;

            

            player.x += player.dx;

            player.y += player.dy;

            

            player.x = Math.max(player.radius, Math.min(CONFIG.canvasWidth - player.radius, player.x));

            player.y = Math.max(player.radius, Math.min(CONFIG.canvasHeight - player.radius, player.y));

            

            let collided = false;

            gameState.walls.forEach(wall => {

                if (circleRectCollision(player, wall)) {

                    collided = true;

                    if (player.dx > 0 && player.x - player.radius < wall.x) {

                        player.x = wall.x - player.radius;

                    } else if (player.dx < 0 && player.x + player.radius > wall.x + wall.width) {

                        player.x = wall.x + wall.width + player.radius;

                    }

                    

                    if (player.dy > 0 && player.y - player.radius < wall.y) {

                        player.y = wall.y - player.radius;

                    } else if (player.dy < 0 && player.y + player.radius > wall.y + wall.height) {

                        player.y = wall.y + wall.height + player.radius;

                    }

                }

            });

            

            if (!collided) {

                for (const wall of gameState.walls) {

                    if (circleRectCollision(player, wall)) {

                        player.x = oldX;

                        player.y = oldY;

                        break;

                    }

                }

            }

            

            // 更新敌人位置

            gameState.enemies.forEach(enemy => {

                const angle = Math.atan2(player.y - enemy.y, player.x - enemy.x);

                const nextX = enemy.x + Math.cos(angle) * difficultySettings.enemySpeed;

                const nextY = enemy.y + Math.sin(angle) * difficultySettings.enemySpeed;

                

                if (gameState.difficulty === 'easy') {

                    let canMove = true;

                    

                    for (const wall of gameState.walls) {

                        if (circleRectCollision({x: nextX, y: nextY, radius: enemy.radius}, wall)) {

                            canMove = false;

                            break;

                        }

                    }

                    

                    if (canMove) {

                        enemy.x = nextX;

                        enemy.y = nextY;

                    }

                } else {

                    enemy.x = nextX;

                    enemy.y = nextY;

                    

                    gameState.walls.forEach(wall => {

                        if (circleRectCollision(enemy, wall)) {

                            if (enemy.x - enemy.radius < wall.x) {

                                enemy.x = wall.x + enemy.radius;

                            } else if (enemy.x + enemy.radius > wall.x + wall.width) {

                                enemy.x = wall.x + wall.width - enemy.radius;

                            }

                            

                            if (enemy.y - enemy.radius < wall.y) {

                                enemy.y = wall.y + enemy.radius;

                            } else if (enemy.y + enemy.radius > wall.y + wall.height) {

                                enemy.y = wall.y + wall.height - enemy.radius;

                            }

                        }

                    });

                }

                

                if (gameState.invincible <= 0 && 

                    circleCircleCollision(player, enemy)) {

                    playerHit();

                }

            });

            

            // 钥匙收集

            gameState.keys.forEach(key => {

                if (!key.collected && circleCircleCollision(player, key)) {

                    key.collected = true;

                    gameState.keysCollected++;

                    keysElement.textContent = gameState.keysCollected;

                    playSound('collect');

                    

                    for (let i = 0; i < 15; i++) {

                        gameState.particles.push({

                            x: key.x,

                            y: key.y,

                            vx: (Math.random() - 0.5) * 4,

                            vy: (Math.random() - 0.5) * 4,

                            life: 30,

                            color: '#FFD700'

                        });

                    }

                }

            });

            

// ✅ 新出口检测:玩家中心碰线即通关

if (gameState.keysCollected >= CONFIG.keysRequired) {

    const exitLineX = CONFIG.canvasWidth - 40; // 出口左边线

    if (gameState.player.x >= exitLineX) {

        endGame(true);

    }

}

 

            

            if (gameState.invincible > 0) {

                gameState.invincible--;

            }

            

            gameState.particles = gameState.particles.filter(p => {

                p.x += p.vx;

                p.y += p.vy;

                p.life--;

                return p.life > 0;

            });

        }

        

        // 渲染游戏

        function render() {

            ctx.clearRect(0, 0, CONFIG.canvasWidth, CONFIG.canvasHeight);

            

            ctx.fillStyle = '#0d1b2a';

            ctx.fillRect(0, 0, CONFIG.canvasWidth, CONFIG.canvasHeight);

            

            ctx.fillStyle = '#415a77';

            gameState.walls.forEach(wall => {

                ctx.fillRect(wall.x, wall.y, wall.width, wall.height);

            });

            

            ctx.fillStyle = gameState.keysCollected >= CONFIG.keysRequired ? '#4CAF50' : '#777';

            ctx.fillRect(CONFIG.canvasWidth - 40, CONFIG.canvasHeight - 40, 40, 40);

            ctx.fillStyle = 'white';

            ctx.font = '12px Arial';

            ctx.textAlign = 'center';

            ctx.fillText('出口', CONFIG.canvasWidth - 20, CONFIG.canvasHeight - 20);

            

            ctx.fillStyle = '#FFD700';

            gameState.keys.forEach(key => {

                if (!key.collected) {

                    ctx.beginPath();

                    ctx.arc(key.x, key.y, key.radius, 0, Math.PI * 2);

                    ctx.fill();

                }

            });

            

            ctx.fillStyle = '#f44336';

            gameState.enemies.forEach(enemy => {

                ctx.beginPath();

                ctx.arc(enemy.x, enemy.y, enemy.radius, 0, Math.PI * 2);

                ctx.fill();

                

                ctx.fillStyle = 'white';

                ctx.beginPath();

                ctx.arc(enemy.x - 3, enemy.y - 2, 2, 0, Math.PI * 2);

                ctx.arc(enemy.x + 3, enemy.y - 2, 2, 0, Math.PI * 2);

                ctx.fill();

                

                ctx.fillStyle = '#f44336';

            });

            

            ctx.fillStyle = gameState.invincible % 6 < 3 ? '#4CAF50' : '#81C784';

            ctx.beginPath();

            ctx.arc(gameState.player.x, gameState.player.y, gameState.player.radius, 0, Math.PI * 2);

            ctx.fill();

            

            ctx.fillStyle = 'white';

            ctx.beginPath();

            ctx.arc(gameState.player.x - 2, gameState.player.y - 1, 1.5, 0, Math.PI * 2);

            ctx.arc(gameState.player.x + 2, gameState.player.y - 1, 1.5, 0, Math.PI * 2);

            ctx.fill();

            

            gameState.particles.forEach(p => {

                ctx.fillStyle = p.color;

                ctx.globalAlpha = p.life / 30;

                ctx.fillRect(p.x - 2, p.y - 2, 4, 4);

            });

            ctx.globalAlpha = 1;

            

            if (gameState.paused) {

                ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';

                ctx.fillRect(0, 0, CONFIG.canvasWidth, CONFIG.canvasHeight);

                ctx.fillStyle = 'white';

                ctx.font = 'bold 24px Arial';

                ctx.textAlign = 'center';

                ctx.fillText('游戏暂停', CONFIG.canvasWidth / 2, CONFIG.canvasHeight / 2);

            }

        }

        

        // 玩家被击中

        function playerHit() {

            gameState.lives--;

            gameState.invincible = 60;

            hpElement.textContent = gameState.lives;

            playSound('hit');

            

            for (let i = 0; i < 20; i++) {

                gameState.particles.push({

                    x: gameState.player.x,

                    y: gameState.player.y,

                    vx: (Math.random() - 0.5) * 5,

                    vy: (Math.random() - 0.5) * 5,

                    life: 30,

                    color: '#f44336'

                });

            }

            

            const angle = Math.atan2(gameState.player.y - CONFIG.canvasHeight/2, 

                                   gameState.player.x - CONFIG.canvasWidth/2);

            gameState.player.x += Math.cos(angle) * 30;

            gameState.player.y += Math.sin(angle) * 30;

            

            if (gameState.lives <= 0) {

                endGame(false);

            }

        }

        

        // 结束游戏

        function endGame(win) {

            gameState.gameOver = true;

            

            // 计算得分

            const difficultySettings = DIFFICULTY[gameState.difficulty];

            let roundScore = 0;

            

            if (win) {

                // 基础分 + 时间分 + 生命分 + 难度乘数

                roundScore = 1000 + 

                           (gameState.timeLeft * 10) + 

                           (gameState.lives * 200);

                roundScore *= difficultySettings.scoreMultiplier;

                

                resultMessage.textContent = '逃脱成功!';

                resultMessage.style.color = '#4CAF50';

                resultDetails.textContent = `你成功收集了所有钥匙并逃出了迷宫!`;

                playSound('win');

            } else {

                // 失败也有参与分

                roundScore = gameState.keysCollected * 100 * difficultySettings.scoreMultiplier;

                

                resultMessage.textContent = '游戏结束';

                resultMessage.style.color = '#f44336';

                resultDetails.textContent = `时间耗尽或生命值归零!`;

                playSound('lose');

            }

            

            gameState.currentRoundScore = roundScore;

            gameState.totalScore += roundScore;

            

            roundScoreElement.textContent = roundScore;

            totalScoreEndElement.textContent = gameState.totalScore;

            

            gameScreen.style.display = 'none';

            endScreen.style.display = 'flex';

        }

        

        // 播放音效

        function playSound(type) {

            if (muted || !audioContext) return;

            

            try {

                const oscillator = audioContext.createOscillator();

                const gainNode = audioContext.createGain();

                

                oscillator.connect(gainNode);

                gainNode.connect(audioContext.destination);

                

                let frequency = 440;

                let duration = 0.1;

                

                switch(type) {

                    case 'collect':

                        frequency = 1000;

                        duration = 0.2;

                        break;

                    case 'hit':

                        frequency = 300;

                        duration = 0.3;

                        oscillator.type = 'sawtooth';

                        break;

                    case 'win':

                        frequency = 523;

                        const frequencies = [523, 659, 784, 1047];

                        frequencies.forEach((freq, i) => {

                            setTimeout(() => {

                                const osc = audioContext.createOscillator();

                                const gn = audioContext.createGain();

                                osc.connect(gn);

                                gn.connect(audioContext.destination);

                                osc.frequency.value = freq;

                                osc.type = 'sine';

                                gn.gain.setValueAtTime(0.1, audioContext.currentTime);

                                gn.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.15);

                                osc.start();

                                osc.stop(audioContext.currentTime + 0.15);

                            }, i * 200);

                        });

                        return;

                    case 'lose':

                        frequency = 220;

                        duration = 0.5;

                        oscillator.type = 'sawtooth';

                        break;

                    default:

                        frequency = 800;

                        duration = 0.1;

                }

                

                oscillator.frequency.value = frequency;

                oscillator.type = oscillator.type || 'sine';

                

                gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);

                gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + duration);

                

                oscillator.start();

                oscillator.stop(audioContext.currentTime + duration);

            } catch (e) {

                console.log("Audio error:", e);

            }

        }

        

        // 切换主题

        function switchTheme() {

            gameState.currentTheme = (gameState.currentTheme + 1) % THEMES.length;

            document.body.style.background = THEMES[gameState.currentTheme];

            playSound('click');

        }

        

        // 碰撞检测函数

        function circleCircleCollision(c1, c2) {

            const dx = c1.x - c2.x;

            const dy = c1.y - c2.y;

            const distance = Math.sqrt(dx * dx + dy * dy);

            return distance < c1.radius + c2.radius;

        }

        

        function circleRectCollision(circle, rect) {

            const closestX = Math.max(rect.x, Math.min(circle.x, rect.x + rect.width));

            const closestY = Math.max(rect.y, Math.min(circle.y, rect.y + rect.height));

            const distanceX = circle.x - closestX;

            const distanceY = circle.y - closestY;

            return (distanceX * distanceX + distanceY * distanceY) < (circle.radius * circle.radius);

        }

        

        // 初始化事件监听

        function initEventListeners() {

            document.querySelectorAll('.difficulty-option').forEach(option => {

                option.addEventListener('click', function() {

                    playSound('click');

                    gameState.difficulty = this.getAttribute('data-difficulty');

                    startScreen.style.display = 'none';

                    gameScreen.style.display = 'flex';

                    initGame();

                    startGame();

                });

            });

            

            document.addEventListener('keydown', (e) => {

                if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {

                    gameState.keysPressed[e.key] = true;

                    e.preventDefault();

                }

            });

            

            document.addEventListener('keyup', (e) => {

                if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {

                    gameState.keysPressed[e.key] = false;

                    e.preventDefault();

                }

            });

            

            function setupButtonControl(buttonId, key) {

                const button = document.getElementById(buttonId);

                

                button.addEventListener('mousedown', () => {

                    gameState.keysPressed[key] = true;

                });

                

                button.addEventListener('mouseup', () => {

                    gameState.keysPressed[key] = false;

                });

                

                button.addEventListener('mouseleave', () => {

                    gameState.keysPressed[key] = false;

                });

                

                button.addEventListener('touchstart', (e) => {

                    e.preventDefault();

                    gameState.keysPressed[key] = true;

                });

                

                button.addEventListener('touchend', (e) => {

                    e.preventDefault();

                    gameState.keysPressed[key] = false;

                });

            }

            

            setupButtonControl('up-btn', 'up');

            setupButtonControl('down-btn', 'down');

            setupButtonControl('left-btn', 'left');

            setupButtonControl('right-btn', 'right');

            

            pauseBtn.addEventListener('click', () => {

                playSound('click');

                gameState.paused = !gameState.paused;

                pauseBtn.textContent = gameState.paused ? '继续' : '暂停';

            });

            

            restartGameBtn.addEventListener('click', () => {

                playSound('click');

                initGame();

            });

            

            restartBtn.addEventListener('click', () => {

                playSound('click');

                endScreen.style.display = 'none';

                gameScreen.style.display = 'flex';

                initGame();

                startGame();

            });

            

            menuBtn.addEventListener('click', () => {

                playSound('click');

                endScreen.style.display = 'none';

                startScreen.style.display = 'flex';

            });

            

            muteBtn.addEventListener('click', () => {

                muted = !muted;

                muteBtn.textContent = muted ? '🔇' : '🔊';

                playSound('click');

            });

            

            themeBtn.addEventListener('click', () => {

                switchTheme();

            });

            

            document.addEventListener('touchmove', (e) => {

                if (e.target.tagName !== 'CANVAS') {

                    e.preventDefault();

                }

            }, { passive: false });

        }

        

        // 开始游戏

        function startGame() {

            try {

                audioContext = new (window.AudioContext || window.webkitAudioContext)();

            } catch (e) {

                console.log("Web Audio API not supported");

            }

            

            const timer = setInterval(() => {

                if (gameState.gameOver || gameState.paused) {

                    if (gameState.gameOver) clearInterval(timer);

                    return;

                }

                

                gameState.timeLeft--;

                timeElement.textContent = gameState.timeLeft;

                

                if (gameState.timeLeft <= 0) {

                    endGame(false);

                    clearInterval(timer);

                }

            }, 1000);

            

            gameLoop();

        }

        

        window.addEventListener('load', () => {

            initEventListeners();

        });

    </script>

</body>

</html>

 

http://www.dtcms.com/a/610101.html

相关文章:

  • 手机网站开发成appWordPress博客建站系统
  • 定义舱驾一体新架构:黑芝麻智能武当C1200家族如何成为跨域计算“第一芯”
  • 小白建站东莞网络营销公司
  • SImpack轨道车辆建模练习
  • react项目创建从0到1及安装(ts、axios、路由、redux)
  • 网站怎么做动态背景图片做网站需要准备哪些材料
  • 网站建设分哪几个版块关键词没有排名的网站怎么做
  • 什么是关键字驱动测试(Keyword-Driven Testing)?
  • 颠覆叙事:Google Veo 3.1与Flow如何开启连贯AI动画长视频时代
  • 【运维】Nginx 入门笔记
  • Docker 部署 GitLab 和 GitLab Runner 指南
  • RabbitMQ 跨平台安装与基础使用指南(Windows_macOS_Ubuntu_Docker 全场景)
  • 市城乡规划建设局网站seo搜索引擎优化内容
  • 2025_11_14洛谷【入门1】数据结构刷题小结
  • wordpress打赏链接网站建设 小影seo
  • 哪个网站能学做微商上海建设网站是多少
  • 第34节:反向运动学与角色动画自然化
  • Virtual Ontology:基于语义层的自然语言SQL生成系统技术深度解析
  • Django过时了吗?从ASGI到AI时代的思考
  • 网站建设需求和页面需求怎么提5m带宽做视频网站
  • 图论专题(六):“隐式图”的登场!DFS/BFS 攻克「岛屿数量」
  • 当Rokid遇见BOLON,科技与时尚的这次握手重新定义“眼镜”
  • 图论专题(五):图遍历的“终极考验”——深度「克隆图」
  • 商业网站策划书模板范文asp 网站发布器
  • STM32WB55官方OTA例程
  • [Column] How Databricks Implemented Intelligent K8s Load Balancing
  • 网站建设好多钱菏泽郓城网站建设
  • 做互联网营销一般上什么网站cms系统都有哪些
  • 【算法】回溯算法精讲:从深度优先搜索到剪枝优化​
  • C语言知识体系梳理-第一篇