多的不说,先看效果
具体实现如下:
1. HTML 结构
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇游戏</title>
<style>
/* CSS 样式 */
</style>
</head>
<body>
<header>
<h1>贪吃蛇游戏</h1>
</header>
<div class="game-container">
<canvas id="gameCanvas" width="600" height="400"></canvas>
<div class="score">当前得分:<span id="score">0</span></div>
<div id="gameOverMessage" class="game-over">游戏结束</div>
<button id="restartButton" class="restart-button">重新开始</button>
</div>
<script>
/* JavaScript 代码 */
</script>
</body>
</html>
2. CSS 样式
body {
font-family: Arial, sans-serif;
text-align: center;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
header {
background: #333;
color: #fff;
padding: 10px 0;
}
.game-container {
margin: 20px auto;
padding: 20px;
background: #fff;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-width: 800px;
}
canvas {
border: 1px solid #000;
}
.score {
font-size: 24px;
margin-top: 20px;
}
.game-over {
display: none;
font-size: 30px;
color: black;
margin-top: 20px;
}
.restart-button {
display: none;
margin-top: 20px;
padding: 10px 20px;
font-size: 18px;
color: white;
background-color: #007bff;
border: none;
border-radius: 5px;
cursor: pointer;
}
.restart-button:hover {
background-color: #0056b3;
}
样式解释:
- body: 设置了页面的字体、背景色、对齐方式等。
- header: 定义了页面标题的背景色和字体颜色。
- .game-container: 游戏区域的容器,设置了背景、边距、内边距、圆角和阴影。
- canvas: 设置了画布的边框。
- .score: 显示得分的样式。
- .game-over: 游戏结束时的提示信息,初始状态为隐藏。
- .restart-button: 重新开始按钮的样式,初始状态为隐藏。
3. JavaScript 代码
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreDisplay = document.getElementById('score');
const gameOverMessage = document.getElementById('gameOverMessage');
const restartButton = document.getElementById('restartButton');
const gridSize = 20; // 网格大小
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
let snake, food, dx, dy, score, changingDirection, gameOver;
function initGame() {
snake = [{x: 200, y: 200}, {x: 180, y: 200}, {x: 160, y: 200}];
food = {x: 300, y: 200};
dx = gridSize; // 水平移动速度
dy = 0; // 垂直移动速度
score = 0;
changingDirection = false;
gameOver = false;
gameOverMessage.style.display = 'none';
restartButton.style.display = 'none';
scoreDisplay.textContent = score;
main();
}
function draw() {
if (gameOver) return;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// 画蛇
ctx.fillStyle = 'green';
snake.forEach(part => ctx.fillRect(part.x, part.y, gridSize, gridSize));
// 画食物
ctx.fillStyle = 'red';
ctx.fillRect(food.x, food.y, gridSize, gridSize);
// 更新蛇的位置
let head = {x: snake[0].x + dx, y: snake[0].y + dy};
snake.unshift(head);
// 检查蛇是否吃到食物
if (head.x === food.x && head.y === food.y) {
score += 10;
scoreDisplay.textContent = score;
placeFood();
} else {
snake.pop();
}
// 检查蛇是否撞墙或自己
if (head.x < 0 || head.x >= canvasWidth || head.y < 0 || head.y >= canvasHeight ||
snake.some((part, index) => index !== 0 && part.x === head.x && part.y === head.y)) {
gameOver = true;
gameOverMessage.style.display = 'block';
restartButton.style.display = 'block';
}
changingDirection = false;
}
function placeFood() {
food = {
x: Math.floor(Math.random() * (canvasWidth / gridSize)) * gridSize,
y: Math.floor(Math.random() * (canvasHeight / gridSize)) * gridSize
};
}
function changeDirection(event) {
if (changingDirection) return;
changingDirection = true;
const keyPressed = event.key;
if (keyPressed === 'ArrowUp' && dy === 0) {
dx = 0;
dy = -gridSize;
} else if (keyPressed === 'ArrowDown' && dy === 0) {
dx = 0;
dy = gridSize;
} else if (keyPressed === 'ArrowLeft' && dx === 0) {
dx = -gridSize;
dy = 0;
} else if (keyPressed === 'ArrowRight' && dx === 0) {
dx = gridSize;
dy = 0;
}
}
function main() {
draw();
if (!gameOver) {
setTimeout(main, 100); // 控制游戏速度
}
}
function restartGame() {
initGame();
}
document.addEventListener('keydown', changeDirection);
restartButton.addEventListener('click', restartGame);
initGame();
JavaScript 代码解释:
-
全局变量:
canvas
和ctx
: 画布和绘图上下文。scoreDisplay
,gameOverMessage
,restartButton
: 页面元素。gridSize
: 网格的大小,用于蛇的每一部分和食物的尺寸。canvasWidth
和canvasHeight
: 画布的宽度和高度。snake
,food
,dx
,dy
,score
,changingDirection
,gameOver
: 游戏状态变量。
-
initGame
:- 初始化游戏的状态,包括蛇的位置、食物的位置、速度、得分等。
- 隐藏游戏结束信息和重新开始按钮。
- 调用
main
函数开始游戏循环。
-
draw
:- 清空画布并绘制蛇和食物。
- 更新蛇的位置。
- 检查蛇是否吃到食物,如果吃到则更新得分并重新放置食物。
- 检查蛇是否撞墙或撞到自己,如果是则游戏结束,并显示游戏结束信息和重新开始按钮。
-
placeFood
:- 随机生成新的食物位置。
-
changeDirection
:- 根据键盘事件改变蛇的移动方向,但防止蛇反向移动。
-
main
:- 调用
draw
函数更新游戏状态,并通过setTimeout
控制游戏速度。
- 调用
-
restartGame
:- 调用
initGame
函数重新初始化游戏,开始新的游戏。
- 调用
-
事件监听:
keydown
事件用于改变蛇的方向。click
事件用于重新开始游戏。
这个代码实现了一个简单的贪吃蛇游戏,其中包括了蛇的移动、吃食物、游戏结束检测以及重新开始功能。