在本教程中,我们将逐步构建一个简单的贪吃蛇游戏。这个项目适合初学者,可以帮助你理解HTML、CSS和JavaScript的基础知识,并掌握如何将它们结合起来创建一个完整的游戏。
准备工作
在开始之前,请确保你已经安装了一个代码编辑器(如Visual Studio Code)和一个浏览器(如Chrome或Firefox)。
第一步:创建HTML文件
首先,我们需要一个HTML文件来定义游戏的结构。在你的项目文件夹中创建一个名为index.html的文件,并添加以下代码:
解释
<!DOCTYPE html>:声明文档的类型为 HTML5,帮助浏览器正确渲染页面。
<html lang="en">:定义 HTML 文档的根元素,并指定语言为英文。
<head>:包含文档的元数据和资源链接。
<meta charset="UTF-8">:设置字符编码为 UTF-8,确保网页支持多语言字符。
<meta name="viewport" content="width=device-width, initial-scale=1.0">:确保网页在移动设备上适应宽度,并设置初始缩放级别。
<title>贪吃蛇小游戏</title>:设置网页的标题。
<style>:包含内部 CSS 样式,用于设置页面的样式。
canvas:设置 canvas 元素的背景颜色、显示方式、外边距和边框样式。
#score:为分数显示元素预留了样式设置位置(目前为空)。
<body>:文档主体,包含页面的实际内容。
<canvas id="gameCanvas" width="500" height="500"></canvas>:定义了一个用于绘制游戏的画布,大小为 500x500 像素。
<div id="score">分数: 0</div>:一个显示游戏分数的 div 元素。
<script src="game.js"></script>:引入外部 JavaScript 文件,用于实现游戏逻辑。
第二步:创建JavaScript文件
在你的项目文件夹中创建一个名为game.js的文件,并添加以下代码:
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreDisplay = document.getElementById('score');
const eatSound = document.getElementById('eatSound');
const gridSize = 20;
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
const gridWidth = canvasWidth / gridSize;
const gridHeight = canvasHeight / gridSize;
let snake = [{ x: 10, y: 10 }];
let food = generateFood();
let dx = 1, dy = 0;
let score = 0;
let speed = 100; // 游戏速度 (毫秒)
let gameInterval;
let isPaused = false; // 暂停状态
document.addEventListener('keydown', changeDirection);
document.addEventListener('keydown', controlGame);
startGame();
function changeDirection(e) {
switch (e.keyCode) {
case 37: // 左箭头
if (dx === 0) { dx = -1; dy = 0; }
break;
case 38: // 上箭头
if (dy === 0) { dx = 0; dy = -1; }
break;
case 39: // 右箭头
if (dx === 0) { dx = 1; dy = 0; }
break;
case 40: // 下箭头
if (dy === 0) { dx = 0; dy = 1; }
break;
}
}
function controlGame(e) {
switch (e.keyCode) {
case 80: // 'P' 键
togglePause();
break;
case 187: // '+' 键
speed = Math.max(10, speed - 10); // 增加速度
updateGameSpeed();
break;
case 189: // '-' 键
speed += 10; // 减少速度
updateGameSpeed();
break;
}
}
function startGame() {
gameInterval = setInterval(loop, speed);
}
function loop() {
if (isPaused) return;
const head = { ...snake[0] };
head.x += dx;
head.y += dy;
// 碰撞检测
if (head.x < 0 || head.x >= gridWidth || head.y < 0 || head.y >= gridHeight ||
snakeCollision(head)) {
endGame();
return;
}
snake.unshift(head);
// 检查是否吃到食物
if (snake[0].x === food.x && snake[0].y === food.y) {
score += 10; // 增加分数
scoreDisplay.textContent = `分数: ${score}`;
eatSound.play(); // 播放音效
food = generateFood(); // 生成新的食物
} else {
snake.pop();
}
drawGame();
}
function drawGame() {
ctx.fillStyle = '#f4f4f4';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.fillStyle = 'red';
ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize, gridSize);
ctx.fillStyle = 'green';
snake.forEach(segment => {
ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize);
});
}
function snakeCollision(head) {
for (let i = 1; i < snake.length; i++) {
if (head.x === snake[i].x && head.y === snake[i].y) {
return true;
}
}
return false;
}
function generateFood() {
let foodPosition;
while (true) {
foodPosition = { x: Math.floor(Math.random() * gridWidth), y:
Math.floor(Math.random() * gridHeight) };
if (!snakeCollision(foodPosition)) break; // 确保食物不出现在蛇身上
}
return foodPosition;
}
function endGame() {
clearInterval(gameInterval);
alert(`游戏结束!你的得分是: ${score}`);
resetGame();
}
function resetGame() {
snake = [{ x: 10, y: 10 }];
dx = 1;
dy = 0;
score = 0;
scoreDisplay.textContent = `分数: ${score}`;
food = generateFood();
startGame();
}
function togglePause() {
isPaused = !isPaused;
if (!isPaused) {
startGame();
} else {
clearInterval(gameInterval);
}
}
function updateGameSpeed() {
clearInterval(gameInterval);
startGame();
}