snake / index.html
erdes's picture
增加一个全屏显示,增加啊沉浸感 - Follow Up Deployment
3389b4e verified
Raw
History Blame Contribute Delete
39.9 kB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇游戏 - Snake Customizer</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
:root {
--grid-size: 20px;
--grid-color: #374151;
--snake-color: #10B981;
--food-color: #EF4444;
--obstacle-color: #6B7280;
--bg-color: #111827;
--speed: 150;
}
.game-container {
position: relative;
background-color: var(--bg-color);
background-image:
linear-gradient(var(--grid-color) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
background-size: var(--grid-size) var(--grid-size);
}
.snake-head {
background-color: var(--snake-color);
border-radius: 4px;
box-shadow: 0 0 5px rgba(16, 185, 129, 0.7);
}
.snake-body {
background-color: var(--snake-color);
border-radius: 2px;
}
.food {
background-color: var(--food-color);
border-radius: 50%;
box-shadow: 0 0 8px rgba(239, 68, 68, 0.8);
animation: pulse 1.5s infinite;
}
.obstacle {
background-color: var(--obstacle-color);
border-radius: 3px;
}
.retro-font {
font-family: 'Press Start 2P', cursive;
}
.custom-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #10B981;
cursor: pointer;
}
.custom-slider::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: #10B981;
cursor: pointer;
}
.color-preview {
width: 30px;
height: 30px;
border-radius: 4px;
cursor: pointer;
}
.settings-panel {
transition: transform 0.3s ease-in-out;
}
.settings-panel.hidden {
transform: translateX(100%);
}
.game-over {
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(4px);
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
@keyframes snakeMove {
0% { transform: scale(0.9); }
50% { transform: scale(1); }
100% { transform: scale(0.9); }
}
</style>
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<!-- 标题区域 -->
<header class="py-4 px-6 bg-gray-800 border-b border-green-500">
<div class="container mx-auto flex justify-between items-center">
<h1 class="text-2xl md:text-3xl font-bold text-green-400 retro-font flex items-center">
<i class="fas fa-snake mr-3"></i>贪吃蛇游戏 - Snake Customizer
</h1>
<div class="flex items-center space-x-2">
<span id="score-display" class="bg-gray-700 px-4 py-2 rounded-lg text-green-300 retro-font">分数: 0</span>
<button id="fullscreen-btn" class="bg-gray-600 hover:bg-gray-500 text-white p-2 rounded-lg transition" title="全屏">
<i class="fas fa-expand"></i>
</button>
<button id="settings-toggle" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg transition">
<i class="fas fa-cog"></i> 设置
</button>
</div>
</div>
</header>
<!-- 主内容区 -->
<main class="flex-grow flex flex-col md:flex-row container mx-auto px-4 py-6 gap-6">
<!-- 游戏区域 -->
<div class="flex-grow flex flex-col items-center">
<div class="game-container w-full max-w-2xl h-96 md:h-[500px] rounded-xl overflow-hidden border-2 border-green-500 relative" id="game-canvas">
<!-- 游戏结束提示 -->
<div id="game-over" class="game-over absolute inset-0 flex flex-col items-center justify-center hidden">
<h2 class="text-3xl font-bold text-red-500 mb-4 retro-font">游戏结束!</h2>
<p class="text-xl text-green-300 mb-6 retro-font">最终分数: <span id="final-score">0</span></p>
<button id="restart-btn" class="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-lg text-xl transition">
<i class="fas fa-redo mr-2"></i>重新开始
</button>
</div>
</div>
<!-- 控制按钮 -->
<div class="mt-6 flex flex-wrap justify-center gap-4">
<button id="start-btn" class="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-lg text-lg transition">
<i class="fas fa-play mr-2"></i>开始游戏
</button>
<button id="pause-btn" class="bg-yellow-600 hover:bg-yellow-700 text-white px-6 py-3 rounded-lg text-lg transition">
<i class="fas fa-pause mr-2"></i>暂停
</button>
<button id="reset-btn" class="bg-red-600 hover:bg-red-700 text-white px-6 py-3 rounded-lg text-lg transition">
<i class="fas fa-sync mr-2"></i>重置
</button>
</div>
<!-- 移动设备控制 -->
<div class="mt-6 grid grid-cols-3 gap-2 w-64">
<div></div>
<button id="up-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg text-center">
<i class="fas fa-arrow-up"></i>
</button>
<div></div>
<button id="left-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg text-center">
<i class="fas fa-arrow-left"></i>
</button>
<div></div>
<button id="right-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg text-center">
<i class="fas fa-arrow-right"></i>
</button>
<div></div>
<button id="down-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg text-center">
<i class="fas fa-arrow-down"></i>
</div>
</div>
</div>
<!-- 设置面板 -->
<div id="settings-panel" class="settings-panel w-full md:w-80 bg-gray-800 rounded-xl p-6 border border-green-500 h-fit">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold text-green-400"><i class="fas fa-sliders-h mr-2"></i>游戏设置</h2>
<button id="close-settings" class="text-gray-400 hover:text-white">
<i class="fas fa-times"></i>
</button>
</div>
<div class="space-y-6">
<!-- 难度设置 -->
<div>
<h3 class="text-lg font-semibold mb-2 text-gray-300"><i class="fas fa-tachometer-alt mr-2"></i>难度设置</h3>
<div class="space-y-4">
<div>
<label class="block mb-1 text-gray-400">游戏速度</label>
<div class="flex items-center">
<span class="mr-2 text-sm"></span>
<input type="range" min="50" max="300" value="150" class="custom-slider w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer" id="speed-slider">
<span class="ml-2 text-sm"></span>
</div>
<div class="text-right text-sm text-green-400" id="speed-value">中等</div>
</div>
<div>
<label class="block mb-1 text-gray-400">网格大小</label>
<div class="flex gap-2">
<button data-size="15" class="grid-size-btn flex-1 bg-gray-700 hover:bg-gray-600 py-2 rounded"></button>
<button data-size="20" class="grid-size-btn flex-1 bg-green-600 py-2 rounded"></button>
<button data-size="25" class="grid-size-btn flex-1 bg-gray-700 hover:bg-gray-600 py-2 rounded"></button>
</div>
</div>
</div>
</div>
<!-- 游戏模式 -->
<div>
<h3 class="text-lg font-semibold mb-2 text-gray-300"><i class="fas fa-gamepad mr-2"></i>游戏模式</h3>
<div class="space-y-2">
<label class="flex items-center cursor-pointer">
<input type="checkbox" id="wall-collision" class="form-checkbox h-5 w-5 text-green-500" checked>
<span class="ml-2 text-gray-300">墙壁碰撞</span>
</label>
<label class="flex items-center cursor-pointer">
<input type="checkbox" id="obstacles" class="form-checkbox h-5 w-5 text-green-500">
<span class="ml-2 text-gray-300">添加障碍物</span>
</label>
<label class="flex items-center cursor-pointer">
<input type="checkbox" id="grow-mode" class="form-checkbox h-5 w-5 text-green-500">
<span class="ml-2 text-gray-300">成长模式</span>
</label>
</div>
</div>
<!-- 外观设置 -->
<div>
<h3 class="text-lg font-semibold mb-2 text-gray-300"><i class="fas fa-palette mr-2"></i>外观设置</h3>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block mb-1 text-gray-400">蛇的颜色</label>
<div class="flex gap-2">
<div class="color-preview bg-green-500" data-color="#10B981" title="绿色"></div>
<div class="color-preview bg-blue-500" data-color="#3B82F6" title="蓝色"></div>
<div class="color-preview bg-purple-500" data-color="#8B5CF6" title="紫色"></div>
</div>
</div>
<div>
<label class="block mb-1 text-gray-400">食物颜色</label>
<div class="flex gap-2">
<div class="color-preview bg-red-500" data-color="#EF4444" title="红色"></div>
<div class="color-preview bg-yellow-500" data-color="#F59E0B" title="黄色"></div>
<div class="color-preview bg-pink-500" data-color="#EC4899" title="粉色"></div>
</div>
</div>
<div>
<label class="block mb-1 text-gray-400">网格颜色</label>
<div class="flex gap-2">
<div class="color-preview bg-gray-500" data-color="#6B7280" title="灰色"></div>
<div class="color-preview bg-blue-400" data-color="#60A5FA" title="浅蓝"></div>
<div class="color-preview bg-green-400" data-color="#34D399" title="浅绿"></div>
</div>
</div>
<div>
<label class="block mb-1 text-gray-400">背景颜色</label>
<div class="flex gap-2">
<div class="color-preview bg-gray-900" data-color="#111827" title="深灰"></div>
<div class="color-preview bg-gray-800" data-color="#1F2937" title="中灰"></div>
<div class="color-preview bg-gray-700" data-color="#374151" title="浅灰"></div>
</div>
</div>
</div>
</div>
<!-- 高级设置 -->
<div>
<h3 class="text-lg font-semibold mb-2 text-gray-300"><i class="fas fa-cogs mr-2"></i>高级设置</h3>
<div class="space-y-2">
<div>
<label class="block mb-1 text-gray-400">初始长度</label>
<input type="range" min="3" max="10" value="4" class="custom-slider w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer" id="initial-length">
<div class="text-right text-sm text-green-400" id="length-value">4</div>
</div>
<div>
<label class="block mb-1 text-gray-400">食物数量</label>
<input type="range" min="1" max="5" value="1" class="custom-slider w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer" id="food-count">
<div class="text-right text-sm text-green-400" id="food-count-value">1</div>
</div>
</div>
</div>
</div>
<button id="apply-settings" class="mt-8 w-full bg-green-600 hover:bg-green-700 text-white py-3 rounded-lg text-lg transition">
<i class="fas fa-check-circle mr-2"></i>应用设置
</button>
</div>
</main>
<!-- 游戏说明 -->
<footer class="bg-gray-800 border-t border-green-500 py-6 px-4">
<div class="container mx-auto">
<h2 class="text-xl font-bold text-green-400 mb-4"><i class="fas fa-info-circle mr-2"></i>游戏说明</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-gray-300">
<div class="bg-gray-700 p-4 rounded-lg">
<h3 class="font-semibold text-green-300 mb-2"><i class="fas fa-keyboard mr-2"></i>控制方式</h3>
<p>键盘方向键或WASD控制蛇的移动方向</p>
<p>移动设备可使用屏幕上的方向按钮</p>
</div>
<div class="bg-gray-700 p-4 rounded-lg">
<h3 class="font-semibold text-green-300 mb-2"><i class="fas fa-star mr-2"></i>游戏目标</h3>
<p>控制蛇吃到食物(红色圆点)</p>
<p>每吃到一个食物,蛇身长度增加,分数增加</p>
</div>
<div class="bg-gray-700 p-4 rounded-lg">
<h3 class="font-semibold text-green-300 mb-2"><i class="fas fa-skull mr-2"></i>游戏结束</h3>
<p>蛇撞到墙壁(如果开启墙壁碰撞)</p>
<p>蛇撞到自己的身体</p>
<p>蛇撞到障碍物(如果开启障碍物)</p>
</div>
</div>
</div>
</footer>
<script>
// 游戏状态变量
let game = {
canvas: null,
ctx: null,
gridSize: 20,
width: 0,
height: 0,
snake: [],
direction: 'right',
nextDirection: 'right',
food: [],
obstacles: [],
score: 0,
isRunning: false,
isPaused: false,
gameLoop: null,
speed: 150,
wallCollision: true,
obstaclesEnabled: false,
growMode: false,
initialLength: 4,
foodCount: 1
};
// 颜色设置
const colors = {
snake: '#10B981',
food: '#EF4444',
grid: '#374151',
bg: '#111827',
obstacle: '#6B7280'
};
// DOM 元素
const elements = {
gameContainer: document.getElementById('game-canvas'),
fullscreenBtn: document.getElementById('fullscreen-btn'),
scoreDisplay: document.getElementById('score-display'),
gameOver: document.getElementById('game-over'),
finalScore: document.getElementById('final-score'),
restartBtn: document.getElementById('restart-btn'),
startBtn: document.getElementById('start-btn'),
pauseBtn: document.getElementById('pause-btn'),
resetBtn: document.getElementById('reset-btn'),
settingsPanel: document.getElementById('settings-panel'),
settingsToggle: document.getElementById('settings-toggle'),
closeSettings: document.getElementById('close-settings'),
applySettings: document.getElementById('apply-settings'),
speedSlider: document.getElementById('speed-slider'),
speedValue: document.getElementById('speed-value'),
wallCollision: document.getElementById('wall-collision'),
obstacles: document.getElementById('obstacles'),
growMode: document.getElementById('grow-mode'),
initialLength: document.getElementById('initial-length'),
lengthValue: document.getElementById('length-value'),
foodCount: document.getElementById('food-count'),
foodCountValue: document.getElementById('food-count-value'),
gridSizeBtns: document.querySelectorAll('.grid-size-btn'),
colorPreviews: document.querySelectorAll('.color-preview'),
upBtn: document.getElementById('up-btn'),
downBtn: document.getElementById('down-btn'),
leftBtn: document.getElementById('left-btn'),
rightBtn: document.getElementById('right-btn')
};
// 初始化游戏
function initGame() {
// 获取游戏区域尺寸
const rect = elements.gameContainer.getBoundingClientRect();
game.width = Math.floor(rect.width / game.gridSize) * game.gridSize;
game.height = Math.floor(rect.height / game.gridSize) * game.gridSize;
// 创建画布
game.canvas = document.createElement('canvas');
game.canvas.width = game.width;
game.canvas.height = game.height;
game.canvas.classList.add('absolute');
elements.gameContainer.innerHTML = '';
elements.gameContainer.appendChild(game.canvas);
game.ctx = game.canvas.getContext('2d');
// 重置游戏状态
resetGame();
// 更新CSS变量
updateCSSVariables();
}
// 重置游戏
function resetGame() {
game.snake = [];
game.food = [];
game.obstacles = [];
game.direction = 'right';
game.nextDirection = 'right';
game.score = 0;
game.isRunning = false;
game.isPaused = false;
// 隐藏游戏结束画面
elements.gameOver.classList.add('hidden');
// 更新分数显示
updateScore();
// 创建初始蛇
createSnake();
// 创建食物
createFood();
// 创建障碍物(如果启用)
if (game.obstaclesEnabled) {
createObstacles();
}
// 绘制游戏
drawGame();
}
// 创建蛇
function createSnake() {
game.snake = [];
const startX = Math.floor(game.width / game.gridSize / 4) * game.gridSize;
const startY = Math.floor(game.height / game.gridSize / 2) * game.gridSize;
for (let i = 0; i < game.initialLength; i++) {
game.snake.push({
x: startX - i * game.gridSize,
y: startY
});
}
}
// 创建食物
function createFood() {
for (let i = 0; i < game.foodCount; i++) {
let newFood;
let overlapping;
do {
overlapping = false;
newFood = {
x: Math.floor(Math.random() * (game.width / game.gridSize)) * game.gridSize,
y: Math.floor(Math.random() * (game.height / game.gridSize)) * game.gridSize
};
// 检查是否与蛇重叠
for (const segment of game.snake) {
if (segment.x === newFood.x && segment.y === newFood.y) {
overlapping = true;
break;
}
}
// 检查是否与现有食物重叠
for (const food of game.food) {
if (food.x === newFood.x && food.y === newFood.y) {
overlapping = true;
break;
}
}
// 检查是否与障碍物重叠
for (const obstacle of game.obstacles) {
if (obstacle.x === newFood.x && obstacle.y === newFood.y) {
overlapping = true;
break;
}
}
} while (overlapping);
game.food.push(newFood);
}
}
// 创建障碍物
function createObstacles() {
const obstacleCount = Math.floor((game.width / game.gridSize) * (game.height / game.gridSize) * 0.05);
for (let i = 0; i < obstacleCount; i++) {
let newObstacle;
let overlapping;
do {
overlapping = false;
newObstacle = {
x: Math.floor(Math.random() * (game.width / game.gridSize)) * game.gridSize,
y: Math.floor(Math.random() * (game.height / game.gridSize)) * game.gridSize
};
// 检查是否与蛇重叠
for (const segment of game.snake) {
if (segment.x === newObstacle.x && segment.y === newObstacle.y) {
overlapping = true;
break;
}
}
// 检查是否与食物重叠
for (const food of game.food) {
if (food.x === newObstacle.x && food.y === newObstacle.y) {
overlapping = true;
break;
}
}
// 检查是否与其他障碍物重叠
for (const obstacle of game.obstacles) {
if (obstacle.x === newObstacle.x && obstacle.y === newObstacle.y) {
overlapping = true;
break;
}
}
} while (overlapping);
game.obstacles.push(newObstacle);
}
}
// 移动蛇
function moveSnake() {
if (!game.isRunning || game.isPaused) return;
// 更新方向
game.direction = game.nextDirection;
// 计算新头部位置
const head = {...game.snake[0]};
switch (game.direction) {
case 'up':
head.y -= game.gridSize;
break;
case 'down':
head.y += game.gridSize;
break;
case 'left':
head.x -= game.gridSize;
break;
case 'right':
head.x += game.gridSize;
break;
}
// 检查墙壁碰撞
if (game.wallCollision) {
if (head.x < 0 || head.x >= game.width || head.y < 0 || head.y >= game.height) {
gameOver();
return;
}
} else {
// 穿墙处理
if (head.x < 0) head.x = game.width - game.gridSize;
if (head.x >= game.width) head.x = 0;
if (head.y < 0) head.y = game.height - game.gridSize;
if (head.y >= game.height) head.y = 0;
}
// 检查自身碰撞
for (let i = 0; i < game.snake.length; i++) {
if (head.x === game.snake[i].x && head.y === game.snake[i].y) {
gameOver();
return;
}
}
// 检查障碍物碰撞
if (game.obstaclesEnabled) {
for (const obstacle of game.obstacles) {
if (head.x === obstacle.x && head.y === obstacle.y) {
gameOver();
return;
}
}
}
// 添加新头部
game.snake.unshift(head);
// 检查食物碰撞
let ateFood = false;
for (let i = 0; i < game.food.length; i++) {
if (head.x === game.food[i].x && head.y === game.food[i].y) {
// 移除被吃的食物
game.food.splice(i, 1);
// 增加分数
game.score += 10;
updateScore();
// 创建新食物
createFood();
ateFood = true;
break;
}
}
// 如果没有吃到食物,移除尾部
if (!ateFood && !game.growMode) {
game.snake.pop();
}
// 绘制游戏
drawGame();
}
// 绘制游戏
function drawGame() {
// 清除画布
game.ctx.clearRect(0, 0, game.width, game.height);
// 绘制蛇
for (let i = 0; i < game.snake.length; i++) {
const segment = game.snake[i];
game.ctx.fillStyle = i === 0 ? colors.snake : colors.snake;
game.ctx.fillRect(segment.x, segment.y, game.gridSize, game.gridSize);
// 添加特殊样式
if (i === 0) {
game.ctx.fillStyle = '#047857';
game.ctx.fillRect(segment.x + 2, segment.y + 2, game.gridSize - 4, game.gridSize - 4);
} else {
game.ctx.fillStyle = '#065F46';
game.ctx.fillRect(segment.x + 1, segment.y + 1, game.gridSize - 2, game.gridSize - 2);
}
}
// 绘制食物
for (const food of game.food) {
game.ctx.fillStyle = colors.food;
game.ctx.beginPath();
game.ctx.arc(food.x + game.gridSize/2, food.y + game.gridSize/2, game.gridSize/2 - 1, 0, Math.PI * 2);
game.ctx.fill();
// 添加高光
game.ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
game.ctx.beginPath();
game.ctx.arc(food.x + game.gridSize/3, food.y + game.gridSize/3, game.gridSize/6, 0, Math.PI * 2);
game.ctx.fill();
}
// 绘制障碍物
for (const obstacle of game.obstacles) {
game.ctx.fillStyle = colors.obstacle;
game.ctx.fillRect(obstacle.x, obstacle.y, game.gridSize, game.gridSize);
// 添加纹理
game.ctx.fillStyle = '#4B5563';
game.ctx.fillRect(obstacle.x + 2, obstacle.y + 2, game.gridSize - 4, game.gridSize - 4);
}
}
// 游戏结束
function gameOver() {
game.isRunning = false;
clearInterval(game.gameLoop);
// 显示游戏结束画面
elements.finalScore.textContent = game.score;
elements.gameOver.classList.remove('hidden');
}
// 开始游戏
function startGame() {
if (game.isRunning) return;
game.isRunning = true;
game.isPaused = false;
// 开始游戏循环
game.gameLoop = setInterval(moveSnake, 300 - game.speed);
}
// 暂停游戏
function pauseGame() {
if (!game.isRunning) return;
game.isPaused = !game.isPaused;
if (game.isPaused) {
clearInterval(game.gameLoop);
elements.pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i>继续';
} else {
game.gameLoop = setInterval(moveSnake, 300 - game.speed);
elements.pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i>暂停';
}
}
// 更新分数显示
function updateScore() {
elements.scoreDisplay.textContent = `分数: ${game.score}`;
}
// 更新CSS变量
function updateCSSVariables() {
document.documentElement.style.setProperty('--grid-size', `${game.gridSize}px`);
document.documentElement.style.setProperty('--grid-color', colors.grid);
document.documentElement.style.setProperty('--snake-color', colors.snake);
document.documentElement.style.setProperty('--food-color', colors.food);
document.documentElement.style.setProperty('--obstacle-color', colors.obstacle);
document.documentElement.style.setProperty('--bg-color', colors.bg);
document.documentElement.style.setProperty('--speed', game.speed);
}
// 应用设置
function applySettings() {
// 更新游戏设置
game.speed = parseInt(elements.speedSlider.value);
game.wallCollision = elements.wallCollision.checked;
game.obstaclesEnabled = elements.obstacles.checked;
game.growMode = elements.growMode.checked;
game.initialLength = parseInt(elements.initialLength.value);
game.foodCount = parseInt(elements.foodCount.value);
// 更新速度显示
if (game.speed < 100) {
elements.speedValue.textContent = '慢';
} else if (game.speed < 200) {
elements.speedValue.textContent = '中等';
} else {
elements.speedValue.textContent = '快';
}
// 更新长度显示
elements.lengthValue.textContent = game.initialLength;
// 更新食物数量显示
elements.foodCountValue.textContent = game.foodCount;
// 重新初始化游戏
initGame();
// 关闭设置面板
elements.settingsPanel.classList.add('hidden');
}
// 事件监听器
function setupEventListeners() {
// 键盘控制
document.addEventListener('keydown', (e) => {
if (!game.isRunning) return;
switch (e.key) {
case 'ArrowUp':
case 'w':
case 'W':
if (game.direction !== 'down') game.nextDirection = 'up';
break;
case 'ArrowDown':
case 's':
case 'S':
if (game.direction !== 'up') game.nextDirection = 'down';
break;
case 'ArrowLeft':
case 'a':
case 'A':
if (game.direction !== 'right') game.nextDirection = 'left';
break;
case 'ArrowRight':
case 'd':
case 'D':
if (game.direction !== 'left') game.nextDirection = 'right';
break;
}
});
// 按钮事件
elements.startBtn.addEventListener('click', startGame);
elements.pauseBtn.addEventListener('click', pauseGame);
elements.resetBtn.addEventListener('click', resetGame);
elements.restartBtn.addEventListener('click', resetGame);
// 设置面板事件
elements.settingsToggle.addEventListener('click', () => {
elements.settingsPanel.classList.remove('hidden');
});
elements.closeSettings.addEventListener('click', () => {
elements.settingsPanel.classList.add('hidden');
});
elements.applySettings.addEventListener('click', applySettings);
// 网格大小按钮
elements.gridSizeBtns.forEach(btn => {
btn.addEventListener('click', () => {
elements.gridSizeBtns.forEach(b => b.classList.remove('bg-green-600'));
btn.classList.add('bg-green-600');
game.gridSize = parseInt(btn.dataset.size);
initGame();
});
});
// 颜色选择
elements.colorPreviews.forEach(preview => {
preview.addEventListener('click', () => {
const color = preview.dataset.color;
const role = preview.parentElement.querySelector('label').textContent;
switch (role) {
case '蛇的颜色':
colors.snake = color;
break;
case '食物颜色':
colors.food = color;
break;
case '网格颜色':
colors.grid = color;
break;
case '背景颜色':
colors.bg = color;
break;
}
updateCSSVariables();
drawGame();
});
});
// 滑块事件
elements.speedSlider.addEventListener('input', () => {
const speed = parseInt(elements.speedSlider.value);
if (speed < 100) {
elements.speedValue.textContent = '慢';
} else if (speed < 200) {
elements.speedValue.textContent = '中等';
} else {
elements.speedValue.textContent = '快';
}
});
elements.initialLength.addEventListener('input', () => {
elements.lengthValue.textContent = elements.initialLength.value;
});
elements.foodCount.addEventListener('input', () => {
elements.foodCountValue.textContent = elements.foodCount.value;
});
// 全屏按钮
elements.fullscreenBtn.addEventListener('click', toggleFullscreen);
// 移动设备控制按钮
elements.upBtn.addEventListener('click', () => {
if (game.direction !== 'down') game.nextDirection = 'up';
});
elements.downBtn.addEventListener('click', () => {
if (game.direction !== 'up') game.nextDirection = 'down';
});
elements.leftBtn.addEventListener('click', () => {
if (game.direction !== 'right') game.nextDirection = 'left';
});
elements.rightBtn.addEventListener('click', () => {
if (game.direction !== 'left') game.nextDirection = 'right';
});
}
// 页面加载完成后初始化
window.addEventListener('load', () => {
initGame();
setupEventListeners();
});
// 切换全屏
function toggleFullscreen() {
if (!document.fullscreenElement) {
elements.gameContainer.requestFullscreen().catch(err => {
console.error(`全屏错误: ${err.message}`);
});
elements.fullscreenBtn.innerHTML = '<i class="fas fa-compress"></i>';
elements.fullscreenBtn.setAttribute('title', '退出全屏');
} else {
document.exitFullscreen();
elements.fullscreenBtn.innerHTML = '<i class="fas fa-expand"></i>';
elements.fullscreenBtn.setAttribute('title', '全屏');
}
}
// 监听全屏变化
document.addEventListener('fullscreenchange', () => {
if (!document.fullscreenElement) {
elements.fullscreenBtn.innerHTML = '<i class="fas fa-expand"></i>';
elements.fullscreenBtn.setAttribute('title', '全屏');
}
});
// 响应窗口大小变化
window.addEventListener('resize', initGame);
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=erdes/snake" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>