前四篇都在终端里玩文字游戏,这篇用 pygame 做经典贪吃蛇,首次接触"游戏主循环":每帧重复"处理输入 → 更新状态 → 绘制画面",理解了它,就理解了所有游戏引擎的工作方式。

玩法介绍

蛇由一串方块组成,方向键控制移动;吃到红色食物会变长并加分;撞墙或撞到自己则结束,速度随得分提升。窗口 480×480 像素,分 24×24 格,蛇和食物都按格子移动。

第 1 步:安装 pygame

pygame 是第三方库,先安装再验证:

pip install pygame
python3 -c "import pygame; print(pygame.version.ver)"

输出版本号即安装成功,下面所有代码保存到 snake.py 中运行。

第 2 步:窗口与主循环骨架

初始化 pygame,创建 480×480 窗口,写一个"空转"主循环:每帧填充背景、刷新画面、处理退出事件。这是所有 pygame 程序的基础骨架。

import pygame

W, H = 480, 480
CELL = 20
pygame.init()
screen = pygame.display.set_mode((W, H))
clock = pygame.time.Clock()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    screen.fill((20, 20, 20))
    pygame.display.flip()
    clock.tick(10)        # 每秒 10 帧,先慢一点

pygame.quit()

第 3 步:蛇与食物

蛇用"头部坐标 + 身体方块列表"表示,初始 3 格;食物是随机位置的方块。移动技巧:新头插入列表头部、尾部弹出;吃到食物时不弹尾,蛇就变长。

import random

GRID = W // CELL
snake = [(10, 10), (9, 10), (8, 10)]   # 头在 (10,10),向右排
direction = (1, 0)
food = (random.randint(0, GRID-1), random.randint(0, GRID-1))

第 4 步:键盘控制与碰撞检测

监听 KEYDOWN 事件,按方向键改变 direction。注意防止"直接反向":蛇正在向右时不能按左,否则会撞死自己。

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False
    elif event.type == pygame.KEYDOWN:
        if event.key == pygame.K_UP and direction != (0, 1):
            direction = (0, -1)
        elif event.key == pygame.K_DOWN and direction != (0, -1):
            direction = (0, 1)
        elif event.key == pygame.K_LEFT and direction != (1, 0):
            direction = (-1, 0)
        elif event.key == pygame.K_RIGHT and direction != (-1, 0):
            direction = (1, 0)

每帧再按方向计算新头部:撞墙或撞到自己就结束;吃到食物则刷新食物,否则弹掉尾部。撞自己的检测放在插入头部之后,用 snake[1:] 判断。

head = (snake[0][0] + direction[0], snake[0][1] + direction[1])
if head[0] < 0 or head[0] >= GRID or head[1] < 0 or head[1] >= GRID:
    print("撞墙了,游戏结束!")
    break
snake.insert(0, head)
if head != food:
    snake.pop()

第 5 步:绘制与完整代码

完整可运行版:蛇画成绿色、食物画成红色方块,标题栏实时显示分数,得分越高帧率越快。

import pygame, random

W = H = 480
CELL = 20
GRID = W // CELL

pygame.init()
screen = pygame.display.set_mode((W, H))
clock = pygame.time.Clock()

snake = [(10, 10), (9, 10), (8, 10)]
direction = (1, 0)
food = (random.randint(0, GRID-1), random.randint(0, GRID-1))
score = 0
running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP and direction != (0, 1):
                direction = (0, -1)
            elif event.key == pygame.K_DOWN and direction != (0, -1):
                direction = (0, 1)
            elif event.key == pygame.K_LEFT and direction != (1, 0):
                direction = (-1, 0)
            elif event.key == pygame.K_RIGHT and direction != (-1, 0):
                direction = (1, 0)

    head = (snake[0][0] + direction[0], snake[0][1] + direction[1])
    if head[0] < 0 or head[0] >= GRID or head[1] < 0 or head[1] >= GRID:
        break
    snake.insert(0, head)
    if head == food:
        score += 1
        food = (random.randint(0, GRID-1), random.randint(0, GRID-1))
    else:
        snake.pop()
    if head in snake[1:]:
        break

    screen.fill((20, 20, 20))
    for x, y in snake:
        pygame.draw.rect(screen, (0, 200, 80), (x*CELL, y*CELL, CELL-2, CELL-2))
    pygame.draw.rect(screen, (220, 40, 40), (food[0]*CELL, food[1]*CELL, CELL-2, CELL-2))
    pygame.display.set_caption(f"贪吃蛇 · 分数: {score}")
    pygame.display.flip()
    clock.tick(10 + score // 2)

pygame.quit()
print(f"游戏结束,得分: {score}")

第 6 步:运行与常见问题

保存为 snake.py,运行 python3 snake.py 即可游玩。常见问题:①窗口一闪而过,检查主循环缩进;②方向键没反应,确认焦点在游戏窗口;③太快或太卡,调整 clock.tick 参数(10~30 手感较好)。

💡 改进方向:①结束时显示"游戏结束"画面而不是直接退出;②食物不要生成在蛇身上;③给蛇头画眼睛、给身体加渐变色;④加入障碍物、加速道具,最高分写入文件持久化保存。