推箱子html代码
wy
1月前
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>经典推箱子 | 1000关卡版</title>
<!-- 引入Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- 引入Font Awesome -->
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- 自定义配置 -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#4F46E5',
secondary: '#10B981',
wall: '#4B5563',
box: '#F59E0B',
target: '#EC4899',
player: '#3B82F6',
ground: '#F3F4F6',
success: '#10B981',
},
fontFamily: {
inter: ['Inter', 'system-ui', 'sans-serif'],
},
},
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.cell-shadow {
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
}
.game-shadow {
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
}
.btn-hover {
@apply transition-all duration-300 hover:scale-105 hover:shadow-lg active:scale-95;
}
.animate-bounce-light {
animation: bounce-light 1.5s infinite;
}
@keyframes bounce-light {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
}
.level-progress {
height: 8px;
background: linear-gradient(90deg, #4F46E5 var(--progress, 0%), #E5E7EB 0%);
}
}
</style>
</head>
<body class="font-inter bg-gradient-to-br from-indigo-50 to-purple-50 min-h-screen flex flex-col items-center justify-center p-4 text-gray-800">
<!-- 游戏容器 -->
<div class="max-w-4xl w-full mx-auto bg-white rounded-2xl p-6 game-shadow">
<!-- 游戏标题 -->
<header class="text-center mb-6">
<h1 class="text-[clamp(1.8rem,4vw,2.5rem)] font-bold text-primary mb-2 flex items-center justify-center gap-2">
<i class="fa fa-cube" aria-hidden="true"></i>
经典推箱子 <span class="text-sm bg-primary/10 text-primary px-2 py-1 rounded-full">1000关卡版</span>
</h1>
<p class="text-gray-600">挑战1000个随机生成关卡,锻炼你的空间思维极限!</p>
</header>
<!-- 关卡进度条 -->
<div class="mb-4">
<div class="flex justify-between text-sm text-gray-500 mb-1">
<span>关卡进度</span>
<span id="progressText">1/1000</span>
</div>
<div id="levelProgressBar" class="level-progress rounded-full" style="--progress: 0.1%"></div>
</div>
<!-- 游戏信息栏 -->
<div class="flex flex-wrap justify-between items-center mb-6 gap-4">
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<span class="text-gray-600">步数:</span>
<span id="moveCount" class="text-xl font-bold text-primary">0</span>
</div>
<div class="flex items-center gap-2">
<span class="text-gray-600">关卡:</span>
<span id="currentLevel" class="text-xl font-bold text-primary">1</span>
</div>
<div class="flex items-center gap-2">
<span class="text-gray-600">箱子:</span>
<span id="boxCount" class="text-xl font-bold text-box">0/0</span>
</div>
</div>
<div class="flex gap-3">
<button id="resetBtn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg btn-hover flex items-center gap-2">
<i class="fa fa-refresh" aria-hidden="true"></i>
<span>重置</span>
</button>
<button id="levelSelectBtn" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-lg btn-hover flex items-center gap-2">
<i class="fa fa-list" aria-hidden="true"></i>
<span>跳转关卡</span>
</button>
</div>
</div>
<!-- 游戏区域 -->
<div class="flex justify-center mb-6">
<div id="gameBoard" class="grid gap-0.5 bg-gray-300 p-1 rounded-lg"></div>
</div>
<!-- 移动控制区 (移动端) -->
<div class="md:hidden grid grid-cols-3 gap-3 max-w-xs mx-auto mb-6">
<div class="col-start-2">
<button class="direction-btn w-full p-4 bg-gray-200 rounded-lg btn-hover" data-direction="up">
<i class="fa fa-arrow-up text-xl" aria-hidden="true"></i>
</button>
</div>
<div class="col-start-1 row-start-2">
<button class="direction-btn w-full p-4 bg-gray-200 rounded-lg btn-hover" data-direction="left">
<i class="fa fa-arrow-left text-xl" aria-hidden="true"></i>
</button>
</div>
<div class="col-start-2 row-start-2">
<button class="direction-btn w-full p-4 bg-gray-200 rounded-lg btn-hover" data-direction="down">
<i class="fa fa-arrow-down text-xl" aria-hidden="true"></i>
</button>
</div>
<div class="col-start-3 row-start-2">
<button class="direction-btn w-full p-4 bg-gray-200 rounded-lg btn-hover" data-direction="right">
<i class="fa fa-arrow-right text-xl" aria-hidden="true"></i>
</button>
</div>
</div>
<!-- 游戏说明 -->
<div class="bg-gray-50 p-4 rounded-lg text-sm text-gray-600">
<h3 class="font-bold text-gray-800 mb-2 flex items-center gap-2">
<i class="fa fa-info-circle" aria-hidden="true"></i>
游戏说明
</h3>
<ul class="list-disc pl-5 space-y-1">
<li>桌面端:使用方向键 ↑↓←→ 控制人物移动,R键快速重置</li>
<li>移动端:点击方向按钮控制人物移动</li>
<li>将所有箱子(黄色)推到目标位置(粉色)即可通关</li>
<li>关卡难度随进度递增,支持直接跳转到任意关卡(1-1000)</li>
</ul>
</div>
</div>
<!-- 关卡选择模态框 -->
<div id="levelModal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-2xl p-6 max-w-md w-full mx-4">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold text-primary">跳转至关卡</h2>
<button id="closeModalBtn" class="text-gray-500 hover:text-gray-700">
<i class="fa fa-times text-xl" aria-hidden="true"></i>
</button>
</div>
<div class="mb-4">
<label for="levelInput" class="block text-gray-700 mb-2">输入关卡号 (1-1000)</label>
<div class="flex gap-2">
<input type="number" id="levelInput" min="1" max="1000" value="1"
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/50">
<button id="quickJumpBtn" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-lg btn-hover">
跳转
</button>
</div>
<p class="text-gray-500 text-xs mt-1">当前关卡: <span id="currentLevelDisplay">1</span></p>
</div>
<div class="grid grid-cols-5 gap-2 mb-4">
<!-- 快速选择关卡按钮将动态生成 -->
</div>
<button id="confirmLevelBtn" class="w-full bg-primary hover:bg-primary/90 text-white py-3 rounded-lg btn-hover">
开始游戏
</button>
</div>
</div>
<!-- 胜利模态框 -->
<div id="successModal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-2xl p-6 max-w-md w-full mx-4 text-center">
<div class="text-5xl text-success mb-4 animate-bounce-light">
<i class="fa fa-trophy" aria-hidden="true"></i>
</div>
<h2 class="text-2xl font-bold text-gray-800 mb-2">恭喜通关!</h2>
<p class="text-gray-600 mb-4">
关卡 <span id="successLevel" class="font-bold text-primary">1</span> 完成<br>
总步数: <span id="successMoves" class="font-bold text-primary">0</span> |
效率评级: <span id="efficiencyRating" class="font-bold text-primary">S</span>
</p>
<div class="mb-6">
<div class="flex justify-between text-sm text-gray-500 mb-1">
<span>总体进度</span>
<span id="successProgressText">1/1000</span>
</div>
<div id="successProgressBar" class="level-progress rounded-full"></div>
</div>
<div class="flex gap-3">
<button id="replayLevelBtn" class="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 py-3 rounded-lg btn-hover">
重新挑战
</button>
<button id="nextLevelBtn" class="flex-1 bg-primary hover:bg-primary/90 text-white py-3 rounded-lg btn-hover">
下一关
</button>
</div>
</div>
</div>
<script>
// 游戏常量定义
const CELL_TYPES = {
EMPTY: 0,
WALL: 1,
BOX: 2,
TARGET: 3,
PLAYER: 4,
BOX_ON_TARGET: 5,
PLAYER_ON_TARGET: 6
};
// 方向映射
const DIRECTIONS = {
up: { x: 0, y: -1 },
down: { x: 0, y: 1 },
left: { x: -1, y: 0 },
right: { x: 1, y: 0 }
};
// 游戏配置
const GAME_CONFIG = {
MAX_LEVELS: 1000,
MIN_SIZE: 5, // 最小地图尺寸
MAX_SIZE: 15, // 最大地图尺寸
WALL_DENSITY: 0.2, // 墙壁密度(随关卡递增)
BOX_RATIO: 0.15 // 箱子占空地块比例(随关卡递增)
};
// 游戏状态
let gameState = {
currentLevel: 1,
moveCount: 0,
map: [],
player: { x: 0, y: 0 },
boxes: [],
targets: [],
mapSize: { width: 5, height: 5 },
completedBoxes: 0
};
// DOM 元素
const gameBoard = document.getElementById('gameBoard');
const moveCountEl = document.getElementById('moveCount');
const currentLevelEl = document.getElementById('currentLevel');
const boxCountEl = document.getElementById('boxCount');
const resetBtn = document.getElementById('resetBtn');
const levelSelectBtn = document.getElementById('levelSelectBtn');
const levelModal = document.getElementById('levelModal');
const closeModalBtn = document.getElementById('closeModalBtn');
const levelInput = document.getElementById('levelInput');
const currentLevelDisplay = document.getElementById('currentLevelDisplay');
const quickJumpBtn = document.getElementById('quickJumpBtn');
const confirmLevelBtn = document.getElementById('confirmLevelBtn');
const successModal = document.getElementById('successModal');
const successLevelEl = document.getElementById('successLevel');
const successMovesEl = document.getElementById('successMoves');
const efficiencyRatingEl = document.getElementById('efficiencyRating');
const replayLevelBtn = document.getElementById('replayLevelBtn');
const nextLevelBtn = document.getElementById('nextLevelBtn');
const directionBtns = document.querySelectorAll('.direction-btn');
const levelProgressBar = document.getElementById('levelProgressBar');
const progressText = document.getElementById('progressText');
const successProgressBar = document.getElementById('successProgressBar');
const successProgressText = document.getElementById('successProgressText');
const quickLevelBtnsContainer = document.querySelector('.grid.grid-cols-5');
// 生成随机数(包含最小值,不包含最大值)
function random(min, max) {
return Math.random() * (max - min) + min;
}
// 生成随机整数(包含最小值和最大值)
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// 根据关卡计算难度参数
function calculateDifficultyParams(level) {
// 难度因子(0-1之间)
const difficultyFactor = Math.min(1, level / GAME_CONFIG.MAX_LEVELS);
// 地图尺寸(随关卡增长)
const sizeGrowth = Math.floor(difficultyFactor * (GAME_CONFIG.MAX_SIZE - GAME_CONFIG.MIN_SIZE));
const mapSize = GAME_CONFIG.MIN_SIZE + sizeGrowth;
// 墙壁密度(随关卡增长)
const wallDensity = GAME_CONFIG.WALL_DENSITY + (difficultyFactor * 0.15);
// 箱子比例(随关卡增长)
const boxRatio = GAME_CONFIG.BOX_RATIO + (difficultyFactor * 0.1);
return {
mapSize,
wallDensity: Math.min(0.35, wallDensity), // 最大墙壁密度限制
boxRatio: Math.min(0.25, boxRatio) // 最大箱子比例限制
};
}
// 检查位置是否可达(BFS算法)
function isReachable(map, start, end, boxes, mapSize) {
const visited = Array(mapSize.height).fill().map(() => Array(mapSize.width).fill(false));
const queue = [start];
visited[start.y][start.x] = true;
// 箱子位置集合
const boxPositions = new Set(boxes.map(box => `${box.x},${box.y}`));
while (queue.length > 0) {
const { x, y } = queue.shift();
// 到达目标
if (x === end.x && y === end.y) return true;
// 四个方向
Object.values(DIRECTIONS).forEach(({ x: dx, y: dy }) => {
const nx = x + dx;
const ny = y + dy;
// 边界检查
if (nx < 0 || nx >= mapSize.width || ny < 0 || ny >= mapSize.height) return;
// 墙壁检查
if (map[ny][nx] === CELL_TYPES.WALL) return;
// 箱子检查(不能穿过箱子)
if (boxPositions.has(`${nx},${ny}`)) return;
// 未访问过
if (!visited[ny][nx]) {
visited[ny][nx] = true;
queue.push({ x: nx, y: ny });
}
});
}
return false;
}
// 生成随机地图(保证有解)
function generateRandomMap(level) {
const { mapSize, wallDensity, boxRatio } = calculateDifficultyParams(level);
const width = mapSize;
const height = mapSize;
let map = [];
let player = { x: 0, y: 0 };
let boxes = [];
let targets = [];
let emptyCells = [];
// 1. 初始化地图(全空)
for (let y = 0; y < height; y++) {
map[y] = [];
for (let x = 0; x < width; x++) {
// 边界设为墙壁
if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {
map[y][x] = CELL_TYPES.WALL;
} else {
map[y][x] = CELL_TYPES.EMPTY;
emptyCells.push({ x, y });
}
}
}
// 2. 随机生成内部墙壁
const wallCount = Math.floor((width - 2) * (height - 2) * wallDensity);
for (let i = 0; i < wallCount; i++) {
if (emptyCells.length === 0) break;
const randomIndex = randomInt(0, emptyCells.length - 1);
const { x, y } = emptyCells[randomIndex];
// 确保墙壁不会把地图分割成无法通过的区域(简单检查:周围墙壁不超过2个)
let adjacentWalls = 0;
Object.values(DIRECTIONS).forEach(({ x: dx, y: dy }) => {
const nx = x + dx;
const ny = y + dy;
if (map[ny][nx] === CELL_TYPES.WALL) adjacentWalls++;
});
if (adjacentWalls < 3) {
map[y][x] = CELL_TYPES.WALL;
emptyCells.splice(randomIndex, 1);
}
}
// 3. 选择玩家初始位置(随机空单元格)
const playerIndex = randomInt(0, emptyCells.length - 1);
player = { ...emptyCells[playerIndex] };
map[player.y][player.x] = CELL_TYPES.PLAYER;
// 4. 计算箱子数量和目标数量(箱子数 = 目标数)
const boxCount = Math.max(1, Math.floor(emptyCells.length * boxRatio));
// 5. 选择目标位置(确保与玩家位置不同)
const availableTargets = emptyCells.filter(cell => !(cell.x === player.x && cell.y === player.y));
for (let i = 0; i < boxCount && availableTargets.length > 0; i++) {
const randomIndex = randomInt(0, availableTargets.length - 1);
const target = availableTargets[randomIndex];
targets.push({ ...target });
availableTargets.splice(randomIndex, 1);
}
// 6. 选择箱子初始位置(确保与玩家和目标位置不同,且可达)
const availableBoxes = availableTargets.filter(cell =>
!targets.some(target => target.x === cell.x && target.y === cell.y)
);
while (boxes.length < boxCount && availableBoxes.length > 0) {
const randomIndex = randomInt(0, availableBoxes.length - 1);
const boxPos = availableBoxes[randomIndex];
// 临时添加箱子
boxes.push({ ...boxPos });
// 检查所有目标是否可达(玩家能到达目标位置)
const allTargetsReachable = targets.every(target =>
isReachable(map, player, target, boxes, { width, height })
);
// 如果不可达,移除这个箱子
if (!allTargetsReachable) {
boxes.pop();
}
availableBoxes.splice(randomIndex, 1);
}
// 确保箱子数等于目标数(如果不够则减少目标数)
if (boxes.length < targets.length) {
targets = targets.slice(0, boxes.length);
}
return {
map,
player,
boxes,
targets,
width,
height
};
}
// 初始化快速选择关卡按钮
function initQuickLevelButtons() {
quickLevelBtnsContainer.innerHTML = '';
// 生成最近的5个关卡和一些里程碑关卡
const quickLevels = [
Math.max(1, gameState.currentLevel - 2),
Math.max(1, gameState.currentLevel - 1),
gameState.currentLevel,
Math.min(GAME_CONFIG.MAX_LEVELS, gameState.currentLevel + 1),
Math.min(GAME_CONFIG.MAX_LEVELS, gameState.currentLevel + 2),
10, 50, 100, 200, 500, 1000
];
// 去重并排序
const uniqueLevels = [...new Set(quickLevels)].sort((a, b) => a - b);
// 创建按钮
uniqueLevels.forEach(level => {
const btn = document.createElement('button');
btn.className = `level-btn w-full py-2 rounded-lg btn-hover text-sm ${
level === gameState.currentLevel ? 'bg-primary text-white' : 'bg-gray-200 text-gray-800'
}`;
btn.textContent = level;
btn.dataset.level = level;
btn.addEventListener('click', () => {
levelInput.value = level;
document.querySelectorAll('.level-btn').forEach(b => {
b.className = 'level-btn w-full py-2 rounded-lg btn-hover text-sm bg-gray-200 text-gray-800';
});
btn.className = 'level-btn w-full py-2 rounded-lg btn-hover text-sm bg-primary text-white';
});
quickLevelBtnsContainer.appendChild(btn);
});
}
// 初始化游戏
function initGame(levelIndex = 1) {
// 验证关卡号
const level = Math.max(1, Math.min(GAME_CONFIG.MAX_LEVELS, levelIndex));
gameState.currentLevel = level;
// 生成关卡
const { map, player, boxes, targets, width, height } = generateRandomMap(level);
gameState = {
currentLevel: level,
moveCount: 0,
map: JSON.parse(JSON.stringify(map)),
player: { ...player },
boxes: JSON.parse(JSON.stringify(boxes)),
targets: JSON.parse(JSON.stringify(targets)),
mapSize: { width, height },
completedBoxes: calculateCompletedBoxes(boxes, targets)
};
updateUI();
renderGameBoard();
updateProgressBar();
}
// 计算已完成的箱子数
function calculateCompletedBoxes(boxes, targets) {
return boxes.filter(box =>
targets.some(target => target.x === box.x && target.y === box.y)
).length;
}
// 更新UI显示
function updateUI() {
moveCountEl.textContent = gameState.moveCount;
currentLevelEl.textContent = gameState.currentLevel;
currentLevelDisplay.textContent = gameState.currentLevel;
levelInput.value = gameState.currentLevel;
// 更新箱子计数
const totalBoxes = gameState.boxes.length;
const completedBoxes = gameState.completedBoxes;
boxCountEl.textContent = `${completedBoxes}/${totalBoxes}`;
// 更新进度文本
progressText.textContent = `${gameState.currentLevel}/${GAME_CONFIG.MAX_LEVELS}`;
}
// 更新进度条
function updateProgressBar() {
const progress = (gameState.currentLevel / GAME_CONFIG.MAX_LEVELS) * 100;
levelProgressBar.style.setProperty('--progress', `${progress}%`);
// 胜利模态框中的进度条
successProgressBar.style.setProperty('--progress', `${progress}%`);
successProgressText.textContent = `${gameState.currentLevel}/${GAME_CONFIG.MAX_LEVELS}`;
}
// 渲染游戏棋盘
function renderGameBoard() {
const { map, mapSize, player, boxes, targets } = gameState;
const { width, height } = mapSize;
// 设置网格尺寸
gameBoard.style.gridTemplateRows = `repeat(${height}, minmax(0, 1fr))`;
gameBoard.style.gridTemplateColumns = `repeat(${width}, minmax(0, 1fr))`;
// 清空棋盘
gameBoard.innerHTML = '';
// 计算单元格大小(响应式)
const maxWidth = window.innerWidth - 40;
const cellSize = Math.min(60, Math.floor(maxWidth / width));
gameBoard.style.gap = '0.5px';
// 渲染每个单元格
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const cell = document.createElement('div');
cell.className = 'cell aspect-square flex items-center justify-center cell-shadow';
cell.style.width = `${cellSize}px`;
cell.style.height = `${cellSize}px`;
// 确定单元格类型
let cellType = map[y][x];
// 检查是否有箱子在目标上
const hasBox = boxes.some(box => box.x === x && box.y === y);
const isTarget = targets.some(target => target.x === x && target.y === y);
const isPlayer = player.x === x && player.y === y;
if (hasBox && isTarget) cellType = CELL_TYPES.BOX_ON_TARGET;
else if (isPlayer && isTarget) cellType = CELL_TYPES.PLAYER_ON_TARGET;
else if (hasBox) cellType = CELL_TYPES.BOX;
else if (isTarget) cellType = CELL_TYPES.TARGET;
else if (isPlayer) cellType = CELL_TYPES.PLAYER;
// 设置单元格样式和内容
switch(cellType) {
case CELL_TYPES.EMPTY:
cell.classList.add('bg-ground');
break;
case CELL_TYPES.WALL:
cell.classList.add('bg-wall', 'rounded-sm');
break;
case CELL_TYPES.BOX:
cell.classList.add('bg-ground');
cell.innerHTML = '<div class="w-4/5 h-4/5 bg-box rounded-md shadow-md transform transition-transform"></div>';
break;
case CELL_TYPES.TARGET:
cell.classList.add('bg-ground');
cell.innerHTML = '<div class="w-4/5 h-4/5 border-2 border-dashed border-target rounded-md"></div>';
break;
case CELL_TYPES.PLAYER:
cell.classList.add('bg-ground');
cell.innerHTML = '<div class="w-3/5 h-3/5 bg-player rounded-full shadow-md transform transition-transform"></div>';
break;
case CELL_TYPES.BOX_ON_TARGET:
cell.classList.add('bg-ground');
cell.innerHTML = '<div class="w-4/5 h-4/5 bg-box rounded-md shadow-md transform transition-transform ring-2 ring-target ring-inset"></div>';
break;
case CELL_TYPES.PLAYER_ON_TARGET:
cell.classList.add('bg-ground');
cell.innerHTML = '<div class="w-3/5 h-3/5 bg-player rounded-full shadow-md transform transition-transform ring-2 ring-target ring-inset"></div>';
break;
}
gameBoard.appendChild(cell);
}
}
}
// 检查移动是否有效
function isValidMove(dx, dy) {
const { x: px, y: py } = gameState.player;
const nx = px + dx;
const ny = py + dy;
const { width, height } = gameState.mapSize;
// 检查边界
if (nx < 0 || nx >= width || ny < 0 || ny >= height) {
return false;
}
// 检查墙壁
if (gameState.map[ny][nx] === CELL_TYPES.WALL) {
return false;
}
// 检查箱子
const boxIndex = gameState.boxes.findIndex(box => box.x === nx && box.y === ny);
if (boxIndex !== -1) {
// 有箱子,检查箱子是否可以移动
const boxNx = nx + dx;
const boxNy = ny + dy;
// 检查箱子移动边界
if (boxNx < 0 || boxNx >= width || boxNy < 0 || boxNy >= height) {
return false;
}
// 检查箱子移动位置是否是墙壁
if (gameState.map[boxNy][boxNx] === CELL_TYPES.WALL) {
return false;
}
// 检查箱子移动位置是否有其他箱子
const isAnotherBox = gameState.boxes.some(box => box.x === boxNx && box.y === boxNy);
if (isAnotherBox) {
return false;
}
// 箱子可以移动
return true;
}
// 没有箱子,移动有效
return true;
}
// 执行移动
function movePlayer(dx, dy) {
if (!isValidMove(dx, dy)) {
return false;
}
const { x: px, y: py } = gameState.player;
const nx = px + dx;
const ny = py + dy;
// 检查是否需要推动箱子
const boxIndex = gameState.boxes.findIndex(box => box.x === nx && box.y === ny);
if (boxIndex !== -1) {
// 移动箱子
gameState.boxes[boxIndex].x += dx;
gameState.boxes[boxIndex].y += dy;
// 更新完成的箱子数
gameState.completedBoxes = calculateCompletedBoxes(gameState.boxes, gameState.targets);
}
// 移动玩家
gameState.player.x = nx;
gameState.player.y = ny;
// 增加步数
gameState.moveCount++;
// 更新UI
updateUI();
renderGameBoard();
// 检查是否通关
if (checkWin()) {
setTimeout(showSuccessModal, 500);
}
return true;
}
// 检查是否通关
function checkWin() {
return gameState.completedBoxes === gameState.boxes.length && gameState.boxes.length > 0;
}
// 计算效率评级
function calculateEfficiencyRating(moveCount, boxCount) {
const baseMovesPerBox = 15; // 每个箱子的基准步数
const efficiency = (boxCount * baseMovesPerBox) / moveCount;
if (efficiency >= 1.2) return 'S';
if (efficiency >= 1.0) return 'A';
if (efficiency >= 0.8) return 'B';
if (efficiency >= 0.6) return 'C';
return 'D';
}
// 显示胜利模态框
function showSuccessModal() {
const level = gameState.currentLevel;
const moves = gameState.moveCount;
const boxCount = gameState.boxes.length;
const rating = calculateEfficiencyRating(moves, boxCount);
successLevelEl.textContent = level;
successMovesEl.textContent = moves;
efficiencyRatingEl.textContent = rating;
// 设置评级颜色
switch(rating) {
case 'S': efficiencyRatingEl.className = 'font-bold text-purple-600'; break;
case 'A': efficiencyRatingEl.className = 'font-bold text-primary'; break;
case 'B': efficiencyRatingEl.className = 'font-bold text-secondary'; break;
case 'C': efficiencyRatingEl.className = 'font-bold text-box'; break;
case 'D': efficiencyRatingEl.className = 'font-bold text-red-500'; break;
}
// 更新进度条
updateProgressBar();
// 如果是最后一关,修改按钮文本
if (level === GAME_CONFIG.MAX_LEVELS) {
nextLevelBtn.textContent = '重新开始';
} else {
nextLevelBtn.textContent = '下一关';
}
successModal.classList.remove('hidden');
}
// 事件监听
function setupEventListeners() {
// 键盘控制
document.addEventListener('keydown', (e) => {
switch(e.key) {
case 'ArrowUp':
movePlayer(0, -1);
break;
case 'ArrowDown':
movePlayer(0, 1);
break;
case 'ArrowLeft':
movePlayer(-1, 0);
break;
case 'ArrowRight':
movePlayer(1, 0);
break;
case 'r':
case 'R':
initGame(gameState.currentLevel);
break;
}
});
// 重置按钮
resetBtn.addEventListener('click', () => {
initGame(gameState.currentLevel);
});
// 关卡选择按钮
levelSelectBtn.addEventListener('click', () => {
initQuickLevelButtons();
levelModal.classList.remove('hidden');
});
// 关闭模态框
closeModalBtn.addEventListener('click', () => {
levelModal.classList.add('hidden');
});
// 快速跳转按钮
quickJumpBtn.addEventListener('click', () => {
let level = parseInt(levelInput.value);
level = Math.max(1, Math.min(GAME_CONFIG.MAX_LEVELS, level));
levelInput.value = level;
// 更新快速选择按钮状态
document.querySelectorAll('.level-btn').forEach(btn => {
if (parseInt(btn.dataset.level) === level) {
btn.className = 'level-btn w-full py-2 rounded-lg btn-hover text-sm bg-primary text-white';
} else {
btn.className = 'level-btn w-full py-2 rounded-lg btn-hover text-sm bg-gray-200 text-gray-800';
}
});
});
// 确认选择关卡
confirmLevelBtn.addEventListener('click', () => {
const level = parseInt(levelInput.value);
if (!isNaN(level) && level >= 1 && level <= GAME_CONFIG.MAX_LEVELS) {
levelModal.classList.add('hidden');
initGame(level);
} else {
alert('请输入1-1000之间的有效关卡号');
}
});
// 重新挑战
replayLevelBtn.addEventListener('click', () => {
successModal.classList.add('hidden');
initGame(gameState.currentLevel);
});
// 下一关
nextLevelBtn.addEventListener('click', () => {
successModal.classList.add('hidden');
let nextLevel = gameState.currentLevel + 1;
if (nextLevel > GAME_CONFIG.MAX_LEVELS) {
nextLevel = 1; // 回到第一关
}
initGame(nextLevel);
});
// 方向按钮(移动端)
directionBtns.forEach(btn => {
btn.addEventListener('click', () => {
const direction = btn.dataset.direction;
const { x, y } = DIRECTIONS[direction];
movePlayer(x, y);
});
});
// 点击空白处关闭模态框
window.addEventListener('click', (e) => {
if (e.target === levelModal) {
levelModal.classList.add('hidden');
}
if (e.target === successModal) {
successModal.classList.add('hidden');
}
});
// 关卡输入框限制
levelInput.addEventListener('input', () => {
let value = parseInt(levelInput.value) || 1;
value = Math.max(1, Math.min(GAME_CONFIG.MAX_LEVELS, value));
levelInput.value = value;
});
}
// 初始化游戏
document.addEventListener('DOMContentLoaded', () => {
setupEventListeners();
initGame(1);
});
</script>
</body>
</html>
这家伙太懒了,什么也没留下。
收藏的用户(0)
X
正在加载信息~