279 lines
6.6 KiB
JavaScript
279 lines
6.6 KiB
JavaScript
// 游戏配置
|
|
const CONFIG = {
|
|
gridSize: 20, // 网格大小
|
|
canvasSize: 400, // 画布大小
|
|
easySpeed: 150, // 简单模式速度
|
|
mediumSpeed: 100, // 中等模式速度
|
|
hardSpeed: 50 // 困难模式速度
|
|
};
|
|
|
|
// 游戏状态
|
|
let snake = [];
|
|
let food = {};
|
|
let direction = 'right';
|
|
let nextDirection = 'right';
|
|
let score = 0;
|
|
let gameLoop = null;
|
|
let isPaused = false;
|
|
let isGameRunning = false;
|
|
|
|
// DOM 元素
|
|
const canvas = document.getElementById('gameCanvas');
|
|
const ctx = canvas.getContext('2d');
|
|
const scoreElement = document.getElementById('score');
|
|
const startBtn = document.getElementById('startBtn');
|
|
const pauseBtn = document.getElementById('pauseBtn');
|
|
const resetBtn = document.getElementById('resetBtn');
|
|
const difficultySelect = document.getElementById('difficulty');
|
|
|
|
// 初始化游戏
|
|
function initGame() {
|
|
snake = [
|
|
{ x: 5, y: 10 },
|
|
{ x: 4, y: 10 },
|
|
{ x: 3, y: 10 }
|
|
];
|
|
direction = 'right';
|
|
nextDirection = 'right';
|
|
score = 0;
|
|
isPaused = false;
|
|
isGameRunning = false;
|
|
updateScore();
|
|
spawnFood();
|
|
draw();
|
|
}
|
|
|
|
// 生成食物
|
|
function spawnFood() {
|
|
const maxPos = CONFIG.canvasSize / CONFIG.gridSize;
|
|
let newFood;
|
|
|
|
do {
|
|
newFood = {
|
|
x: Math.floor(Math.random() * maxPos),
|
|
y: Math.floor(Math.random() * maxPos)
|
|
};
|
|
} while (snake.some(segment => segment.x === newFood.x && segment.y === newFood.y));
|
|
|
|
food = newFood;
|
|
}
|
|
|
|
// 更新游戏状态
|
|
function update() {
|
|
if (isPaused) return;
|
|
|
|
direction = nextDirection;
|
|
|
|
// 计算蛇头新位置
|
|
const head = { ...snake[0] };
|
|
|
|
switch (direction) {
|
|
case 'up':
|
|
head.y -= 1;
|
|
break;
|
|
case 'down':
|
|
head.y += 1;
|
|
break;
|
|
case 'left':
|
|
head.x -= 1;
|
|
break;
|
|
case 'right':
|
|
head.x += 1;
|
|
break;
|
|
}
|
|
|
|
// 检查碰撞
|
|
if (checkCollision(head)) {
|
|
gameOver();
|
|
return;
|
|
}
|
|
|
|
// 添加蛇头
|
|
snake.unshift(head);
|
|
|
|
// 检查是否吃到食物
|
|
if (head.x === food.x && head.y === food.y) {
|
|
score += 10;
|
|
updateScore();
|
|
spawnFood();
|
|
} else {
|
|
snake.pop();
|
|
}
|
|
|
|
draw();
|
|
}
|
|
|
|
// 检查碰撞
|
|
function checkCollision(head) {
|
|
const maxPos = CONFIG.canvasSize / CONFIG.gridSize;
|
|
|
|
// 撞墙检测
|
|
if (head.x < 0 || head.x >= maxPos || head.y < 0 || head.y >= maxPos) {
|
|
return true;
|
|
}
|
|
|
|
// 撞自己检测
|
|
return snake.some(segment => segment.x === head.x && segment.y === head.y);
|
|
}
|
|
|
|
// 绘制游戏
|
|
function draw() {
|
|
// 清空画布
|
|
ctx.fillStyle = '#2c3e50';
|
|
ctx.fillRect(0, 0, CONFIG.canvasSize, CONFIG.canvasSize);
|
|
|
|
// 绘制蛇
|
|
snake.forEach((segment, index) => {
|
|
const gradient = ctx.createRadialGradient(
|
|
segment.x * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
segment.y * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
0,
|
|
segment.x * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
segment.y * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
CONFIG.gridSize
|
|
);
|
|
|
|
if (index === 0) {
|
|
gradient.addColorStop(0, '#2ecc71');
|
|
gradient.addColorStop(1, '#27ae60');
|
|
} else {
|
|
gradient.addColorStop(0, '#82e0aa');
|
|
gradient.addColorStop(1, '#58d68d');
|
|
}
|
|
|
|
ctx.fillStyle = gradient;
|
|
ctx.fillRect(
|
|
segment.x * CONFIG.gridSize + 1,
|
|
segment.y * CONFIG.gridSize + 1,
|
|
CONFIG.gridSize - 2,
|
|
CONFIG.gridSize - 2
|
|
);
|
|
});
|
|
|
|
// 绘制食物
|
|
const foodGradient = ctx.createRadialGradient(
|
|
food.x * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
food.y * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
0,
|
|
food.x * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
food.y * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
CONFIG.gridSize
|
|
);
|
|
foodGradient.addColorStop(0, '#e74c3c');
|
|
foodGradient.addColorStop(1, '#c0392b');
|
|
|
|
ctx.fillStyle = foodGradient;
|
|
ctx.beginPath();
|
|
ctx.arc(
|
|
food.x * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
food.y * CONFIG.gridSize + CONFIG.gridSize / 2,
|
|
CONFIG.gridSize / 2 - 2,
|
|
0,
|
|
Math.PI * 2
|
|
);
|
|
ctx.fill();
|
|
}
|
|
|
|
// 更新分数
|
|
function updateScore() {
|
|
scoreElement.textContent = score;
|
|
}
|
|
|
|
// 游戏结束
|
|
function gameOver() {
|
|
stopGame();
|
|
alert(`游戏结束!得分:${score}\n点击"重置"重新开始`);
|
|
}
|
|
|
|
// 开始游戏
|
|
function startGame() {
|
|
if (isGameRunning) return;
|
|
|
|
initGame();
|
|
isGameRunning = true;
|
|
startBtn.disabled = true;
|
|
pauseBtn.disabled = false;
|
|
difficultySelect.disabled = true;
|
|
|
|
const speed = getGameSpeed();
|
|
gameLoop = setInterval(update, speed);
|
|
}
|
|
|
|
// 停止游戏
|
|
function stopGame() {
|
|
if (gameLoop) {
|
|
clearInterval(gameLoop);
|
|
gameLoop = null;
|
|
}
|
|
isGameRunning = false;
|
|
startBtn.disabled = false;
|
|
pauseBtn.disabled = true;
|
|
pauseBtn.textContent = '暂停';
|
|
difficultySelect.disabled = false;
|
|
}
|
|
|
|
// 暂停/继续游戏
|
|
function togglePause() {
|
|
if (!isGameRunning) return;
|
|
|
|
isPaused = !isPaused;
|
|
|
|
if (isPaused) {
|
|
pauseBtn.textContent = '继续';
|
|
} else {
|
|
pauseBtn.textContent = '暂停';
|
|
}
|
|
}
|
|
|
|
// 重置游戏
|
|
function resetGame() {
|
|
stopGame();
|
|
initGame();
|
|
}
|
|
|
|
// 获取游戏速度
|
|
function getGameSpeed() {
|
|
const difficulty = difficultySelect.value;
|
|
|
|
switch (difficulty) {
|
|
case 'easy':
|
|
return CONFIG.easySpeed;
|
|
case 'medium':
|
|
return CONFIG.mediumSpeed;
|
|
case 'hard':
|
|
return CONFIG.hardSpeed;
|
|
default:
|
|
return CONFIG.mediumSpeed;
|
|
}
|
|
}
|
|
|
|
// 键盘控制
|
|
document.addEventListener('keydown', (e) => {
|
|
const key = e.key;
|
|
|
|
if (key === 'ArrowUp' && direction !== 'down') {
|
|
nextDirection = 'up';
|
|
e.preventDefault();
|
|
} else if (key === 'ArrowDown' && direction !== 'up') {
|
|
nextDirection = 'down';
|
|
e.preventDefault();
|
|
} else if (key === 'ArrowLeft' && direction !== 'right') {
|
|
nextDirection = 'left';
|
|
e.preventDefault();
|
|
} else if (key === 'ArrowRight' && direction !== 'left') {
|
|
nextDirection = 'right';
|
|
e.preventDefault();
|
|
} else if (key === ' ' && isGameRunning) {
|
|
togglePause();
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
|
|
// 按钮事件
|
|
startBtn.addEventListener('click', startGame);
|
|
pauseBtn.addEventListener('click', togglePause);
|
|
resetBtn.addEventListener('click', resetGame);
|
|
|
|
// 初始化
|
|
initGame();
|