代码是一个用 HTML5 Canvas 和 JavaScript 实现的简单贪吃蛇游戏。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Snake Game</title>
<style>
canvas {
display: block;
margin: 0 auto;
background-color: #000;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="400" height="400"></canvas>
<canvas>
:游戏在一个 400x400 像素的画布上运行,ID 为 gameCanvas
。display: block
和 margin: 0 auto
让画布居中显示。background-color: #000
设置画布背景为黑色。JavaScript 代码控制游戏的逻辑,包括蛇的移动、食物生成、碰撞检测等。
const canvas = documentdocument.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
constconstgridSizeconst gridSize = 20;
constconst tileCount = canvascanvas.width / gridSize;
canvas
:获取画布元素。ctx
:获取 2D 绘图上下文,用于绘制图形。gridSize = 20
:游戏网格的大小,每个蛇身或食物占 20x20 像素。tileCount = 20
:画布宽 400 像素 ÷ 网格大小 20 = 20 个格子,游戏在一个 20x20 的网格中运行。let snake = [{ x: 10, y: 10 }];
let food = { x: Math.floor(Math.random() * tileCount), y: Math.floor(Math.random() * tileCount) };
let direction = { x: 0, y: 0 };
let score = 0;
snake
:蛇是一个数组,初始时只有一节,位于网格坐标 (10, 10)。food
:食物的初始位置在网格中随机生成(0 到 19 的整数)。direction
:蛇的移动方向,初始为静止 { x: 0, y: 0 }
。score
:玩家的得分,初始为 0。function gameLoop() {
update();
draw();
setTimeout(gameLoop, 100);
}
gameLoop();
gameLoop
:主循环,调用 update
(更新游戏状态)和 draw
(绘制画面)。setTimeout(gameLoop, 100)
:每 100 毫秒运行一次循环,控制游戏速度(每秒约 10 次更新)。gameLoop()
启动游戏。function update() {
const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount || snake.some(segment => segment.x === head.x && segment.y === head.y)) {
resetGame();
return;
}
snake.unshift(headhead);
if (head.x === food.x && head.y === food.y) {
score++;
food = { x: Math.floor(Math.random() * tileCount), y: Math.floor(Math.random() * tileCount) };
} else {
snake.pop();
}
}
head
:根据当前方向计算蛇头的新位置(当前蛇头坐标 + 方向)。x < 0
或 x >= tileCount
等)。snake.some(...)
检查蛇头是否与蛇身任一段重合)。resetGame()
重置游戏。snake.unshift(head)
:将新蛇头加入蛇数组头部。score++
:得分加 1。snake.pop()
移除蛇尾,保持蛇长度不变(模拟移动)。function draw() {
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#0f0';
snake.forEach(segment => ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize));
ctx.fillStyle = '#f00';
ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize, gridSize);
ctx.fillStyle = '#fff';
ctx.font = '20px Arial';
ctx.fillText('Score: ' + score, 10, 30);
}
#000
) 填充整个画布,清除上一帧。#0f0
) 绘制蛇的每一段,segment.x * gridSize
将网格坐标转为像素坐标。#f00
) 绘制食物方块。#fff
) 在画布左上角显示得分(Score: X
)。function resetGame() {
snake = [{ x: 10, y: 10 }];
direction = { x: 0, y: 0 };
score = 0;
}
window.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowUp':
if (direction.y === 0) direction = { x: 0, y: -1 };
break;
case 'ArrowDown':
if (direction.y === 0) direction = { x: 0, y: 1 };
break;
case 'ArrowLeft':
if (direction.x === 0) direction = { x: -1, y: 0 };
break;
case 'ArrowRight':
if (direction.x === 0) direction = { x: 1, y: 0 };
break;
}
});
keydown
事件捕获方向键输入。y: -1
(向上移动)。y: 1
(向下移动)。x: -1
(向左移动)。x: 1
(向右移动)。direction.x !== 0
),不能直接向左,if (direction.x === 0)
确保只在水平静止时允许左右移动,防止蛇直接掉头咬自己。