6 分钟·2,332 字·37 次阅读
贪吃蛇小游戏:从零实现一个带排行榜的经典游戏
贪吃蛇小游戏:从零实现一个带排行榜的经典游戏
前言
贪吃蛇是我接触编程时最早想做的游戏之一。规则简单——控制蛇吃食物,不能碰墙也不能碰自己。这次把它做成了一个带排行榜的完整版本,放在博客的 Playground 里。
? 点这里玩贪吃蛇
技术实现
Canvas 绘制
用 HTML5 Canvas 绘制游戏画面,20x20 的网格,蛇和食物都在网格上移动:
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const GRID = 20;
// 绘制蛇身(渐变透明度)
snake.forEach((seg, i) => {
const alpha = 1 - (i / snake.length) * 0.5;
ctx.fillStyle = i === 0 ? '#22d3ee' : `rgba(34, 211, 238, ${alpha})`;
ctx.fillRect(seg.x * GRID + 1, seg.y * GRID + 1, GRID - 2, GRID - 2);
});
蛇头用青色,身体逐渐变淡,形成拖尾效果。
游戏逻辑
核心逻辑很简单:每帧蛇头向前移动一格,如果吃到食物就增长,否则去掉尾巴。
function update() {
const head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
// 碰壁或碰自己 → 游戏结束
if (head.x < 0 || head.x >= COLS || head.y < 0 || head.y >= ROWS ||
snake.some(s => s.x === head.x && s.y === head.y)) {
gameOver();
return;
}
snake.unshift(head);
if (head.x === food.x && head.y === food.y) {
score += 10;
placeFood();
} else {
snake.pop();
}
}
键盘控制
支持方向键和 WASD,加了一个防止反向移动的判断(不能直接掉头):
if (newDir.x !== -dir.x || newDir.y !== -dir.y) {
dir = newDir;
}
还支持空格暂停/继续。
排行榜功能
排行榜用数据库实现,游戏结束时弹出输入框,提交分数后实时更新排行榜。
数据库设计
model SnakeScore {
id String @id @default(cuid())
name String @db.VarChar(50)
score Int
createdAt DateTime @default(now())
@@index([score(sort: Desc)])
}
直接在数据库层按分数降序建索引,查询 Top 10 走索引,不需要内存排序。
API 设计
// GET: 排行榜 Top 10
const scores = await db.snakeScore.findMany({
take: 10,
orderBy: { score: "desc" },
});
// POST: 提交分数
await db.snakeScore.create({
data: { name, score },
});
前端在游戏结束时调用 POST 接口,提交后自动刷新排行榜。
界面设计
深色主题,和博客管理后台风格统一。左侧是游戏区域,右侧是排行榜。
排行榜前三名用金银铜色徽章标识,增加成就感。移动端自动变成上下布局。
一些细节
蛇身渐变:蛇头最亮,身体逐渐变淡,形成拖尾效果。这样即使蛇很长,也能一眼看出蛇头在哪。
蛇头眼睛:在蛇头上画了两个小圆点作为眼睛,方向会跟着移动方向变化。
食物动画:食物用圆形绘制,比方块更好看。
暂停功能:按空格键暂停/继续,暂停时显示"已暂停"状态。
试试看
? 点这里玩贪吃蛇
玩完记得输入名字,登上排行榜!
更新于 2026年8月26日
文章链接: