<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇游戏</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"></link>
<style>
@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.game-board {
display: grid;
grid-template-columns: repeat(30, 20px);
grid-template-rows: repeat(30, 20px);
}
.snake-cell {
background-color: #4ade80;
border-radius: 2px;
}
.food-cell {
background-color: #f87171;
border-radius: 50%;
}
.game-over {
animation: blink 1s infinite;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center p-4">
<div class="bg-white rounded-lg shadow-lg p-6 max-w-2xl w-full">
<h1 class="text-3xl font-bold text-center mb-4">贪吃蛇游戏</h1>
<div class="flex justify-between items-center mb-4">
<div class="text-lg font-semibold">得分: <span id="score">0</span></div>
<div class="flex gap-2">
<button id="startBtn" class="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600">开始</button>
<button id="pauseBtn" class="px-4 py-2 bg-yellow-500 text-white rounded hover:bg-yellow-600" disabled>暂停</button>
<button id="resetBtn" class="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600">重置</button>
</div>
</div>
<div class="flex justify-center mb-4">
<div id="gameBoard" class="game-board border-2 border-gray-300"></div>
</div>
<div class="text-center text-gray-600">
<p>使用方向键 ↑ ↓ ← → 控制蛇的移动</p>
</div>
</div>
<script>
// 游戏常量
const GRID_SIZE = 20;
const BOARD_SIZE = 30;
const INITIAL_SPEED = 100; // 毫秒
// 获取DOM元素
const gameBoard = document.getElementById('gameBoard');
const scoreDisplay = document.getElementById('score');
const startBtn = document.getElementById('startBtn');
const pauseBtn = document.getElementById('pauseBtn');
const resetBtn = document.getElementById('resetBtn');
// 游戏状态
let snake = [[15, 15]]; // 蛇的初始位置
let food = generateFood();
let direction = 'RIGHT';
let score = 0;
let gameInterval;
let gameState = 'idle'; // 'idle', 'running', 'paused', 'over'
// 方向映射
const directionMap = {
'ArrowUp': 'UP',
'ArrowDown': 'DOWN',
'ArrowLeft': 'LEFT',
'ArrowRight': 'RIGHT'
};
// 禁止反向移动
const oppositeDirections = {
'UP': 'DOWN',
'DOWN': 'UP',
'LEFT': 'RIGHT',
'RIGHT': 'LEFT'
};
// 生成食物
function generateFood() {
let newFood;
do {
newFood = [
Math.floor(Math.random() * BOARD_SIZE),
Math.floor(Math.random() * BOARD_SIZE)
];
} while (snake.some(segment => segment[0] === newFood[0] && segment[1] === newFood[1]));
return newFood;
}
// 绘制游戏
function drawGame() {
// 清空游戏板
gameBoard.innerHTML = '';
// 绘制蛇
snake.forEach(segment => {
const cell = document.createElement('div');
cell.className = 'snake-cell';
cell.style.gridColumnStart = segment[0] + 1;
cell.style.gridRowStart = segment[1] + 1;
gameBoard.appendChild(cell);
});
// 绘制食物
const foodCell = document.createElement('div');
foodCell.className = 'food-cell';
foodCell.style.gridColumnStart = food[0] + 1;
foodCell.style.gridRowStart = food[1] + 1;
gameBoard.appendChild(foodCell);
}
// 移动蛇
function moveSnake() {
if (gameState !== 'running') return;
// 获取当前蛇头位置
const [headX, headY] = snake[0];
// 根据方向移动蛇头
let newHead;
switch (direction) {
case 'UP':
newHead = [headX, headY - 1];
break;
case 'DOWN':
newHead = [headX, headY + 1];
break;
case 'LEFT':
newHead = [headX - 1, headY];
break;
case 'RIGHT':
newHead = [headX + 1, headY];
break;
}
// 检查碰撞
if (checkCollision(newHead)) {
endGame();
return;
}
// 添加新头部
snake.unshift(newHead);
// 检查是否吃到食物
if (newHead[0] === food[0] && newHead[1] === food[1]) {
// 吃到食物,增加分数
score++;
scoreDisplay.textContent = score;
// 生成新食物
food = generateFood();
} else {
// 没吃到食物,移除尾部
snake.pop();
}
// 绘制游戏
drawGame();
}
// 检查碰撞
function checkCollision(newHead) {
// 检查是否撞墙
if (newHead[0] < 0 || newHead[0] >= BOARD_SIZE || newHead[1] < 0 || newHead[1] >= BOARD_SIZE) {
return true;
}
// 检查是否撞到自己(除了头部)
for (let i = 1; i < snake.length; i++) {
if (newHead[0] === snake[i][0] && newHead[1] === snake[i][1]) {
return true;
}
}
return false;
}
// 开始游戏
function startGame() {
if (gameState === 'running') return;
resetGame()
gameState = 'running';
startBtn.disabled = true;
pauseBtn.disabled = false;
gameInterval = setInterval(moveSnake, INITIAL_SPEED);
}
// 暂停游戏
function pauseGame() {
if (gameState === 'paused' || gameState === 'idle') return;
gameState = 'paused';
pauseBtn.textContent = '继续';
clearInterval(gameInterval);
}
// 继续游戏
function resumeGame() {
if (gameState !== 'paused') return;
gameState = 'running';
pauseBtn.textContent = '暂停';
gameInterval = setInterval(moveSnake, INITIAL_SPEED);
}
// 结束游戏
function endGame() {
gameState = 'over';
clearInterval(gameInterval);
startBtn.disabled = false;
pauseBtn.disabled = true;
pauseBtn.textContent = '暂停';
// 显示游戏结束
const gameOverMessage = document.createElement('div');
gameOverMessage.className = 'game-over text-2xl font-bold text-red-600';
gameOverMessage.textContent = '游戏结束!';
gameBoard.appendChild(gameOverMessage);
}
// 重置游戏
function resetGame() {
clearInterval(gameInterval);
snake = [[15, 15]];
food = generateFood();
direction = 'RIGHT';
score = 0;
gameState = 'idle';
scoreDisplay.textContent = score;
startBtn.disabled = false;
pauseBtn.disabled = true;
pauseBtn.textContent = '暂停';
// 清空游戏板
gameBoard.innerHTML = '';
drawGame();
}
// 键盘事件监听
document.addEventListener('keydown', (e) => {
if (gameState !== 'running') return;
const newDirection = directionMap[e.key];
if (newDirection && oppositeDirections[direction] !== newDirection) {
direction = newDirection;
}
});
// 按钮事件绑定
startBtn.addEventListener('click', startGame);
pauseBtn.addEventListener('click', () => {
if (gameState === 'paused') {
resumeGame();
} else {
pauseGame();
}
});
resetBtn.addEventListener('click', resetGame);
// 初始绘制
drawGame();
</script>
</body>
</html>
index.html
index.html