海拥✘头像
关注

我用 Seed Evolving 做了个 Python 版贪吃蛇游戏

上一篇我用 Seed Evolving 做了一个金价监控 Agent,这次想换一个轻松一点的方向:做一个 Python 版贪吃蛇小游戏。

因为它不只是“让模型写一段代码”,而是能完整体现 Seed Evolving 在一个小项目里的作用:拆需求、定规则、规划代码结构、补齐游戏循环、处理边界情况,最后生成一个能直接运行的小游戏。

在这里插入图片描述

一、我想做什么

我一开始给 Seed Evolving 的需求很简单:

我想用 Python 做一个贪吃蛇小游戏。
要求能控制蛇移动、吃食物加分、撞墙或撞到自己就结束。
代码最好适合新手阅读,能直接运行。

Seed Evolving 没有直接给我一大坨代码,而是先把需求拆成了几个模块:

  1. 游戏窗口:用 Pygame 创建窗口和主循环。
  2. 蛇的数据结构:用列表保存蛇头和蛇身坐标。
  3. 方向控制:监听方向键或 WASD。
  4. 食物生成:随机生成,不能出现在蛇身上。
  5. 碰撞检测:撞墙或撞到自己就 Game Over。
  6. 分数和重开:吃到食物加分,结束后按 R 重新开始。

这一步很有用,因为小游戏最容易写着写着变成“所有逻辑都塞进 while True”。Seed Evolving 先把结构拆出来,后面写代码就顺很多。

二、整体方案

这次的工具结构可以理解成这样:

Pygame 窗口
   ↓
事件监听:方向键 / WASD / 退出 / 重开
   ↓
游戏状态更新:蛇移动、吃食物、碰撞检测
   ↓
画面渲染:网格、蛇、食物、分数、结束提示

Seed Evolving 在这里主要做了两类事。

第一类是开发指导:

  • 建议用 Pygame 做 2D 小游戏。
  • 建议用“格子坐标”管理蛇和食物,而不是直接用像素坐标。
  • 建议把随机食物、绘制方块、重置游戏拆成函数。
  • 提醒我处理“反向移动”这个经典 bug。

第二类是代码生成:

  • 生成基础游戏循环。
  • 生成键盘控制逻辑。
  • 生成蛇移动和吃食物逻辑。
  • 生成撞墙、撞身体、重开游戏逻辑。

在这里插入图片描述

三、准备环境

这次只需要 Python 和 Pygame。

pip install pygame

运行方式:

python seed_evolving_snake.py

如果是在 VS Code 里,直接打开文件运行也可以。

四、核心实现思路

1. 用格子坐标管理游戏

Seed Evolving 建议不要直接用像素坐标写蛇的位置,而是先定义“每个格子多大”,再让蛇在格子里移动。

CELL_SIZE = 24
COLS = 24
ROWS = 20
WIDTH = CELL_SIZE * COLS
HEIGHT = CELL_SIZE * ROWS

这样蛇头 (10, 8) 表示第 10 列、第 8 行,而不是屏幕上的具体像素点。绘制时再乘以 CELL_SIZE 就行。

2. 用列表保存蛇身

蛇的身体本质上就是一串坐标。列表第一个元素是蛇头,后面的元素是蛇身。

snake = [
    (COLS // 2, ROWS // 2),
    (COLS // 2 - 1, ROWS // 2),
    (COLS // 2 - 2, ROWS // 2),
]
direction = (1, 0)

每次移动时,把新的蛇头插到列表最前面;如果没有吃到食物,就删掉最后一节身体。

3. 随机生成食物

食物不能出现在蛇身上,所以生成后要检查一下。

def random_food(snake):
    while True:
        pos = (random.randint(0, COLS - 1), random.randint(0, ROWS - 1))
        if pos not in snake:
            return pos

这段是 Seed Evolving 特别提醒我的地方:如果不判断 pos not in snake,食物可能直接刷在蛇身下面,看起来就像“凭空消失”。

4. 处理方向控制

方向控制除了监听按键,还要避免蛇直接反向。例如蛇正在向右走时,不能马上向左,否则会直接撞到自己。

if event.key in (pygame.K_UP, pygame.K_w) and direction != (0, 1):
    direction = (0, -1)
elif event.key in (pygame.K_DOWN, pygame.K_s) and direction != (0, -1):
    direction = (0, 1)
elif event.key in (pygame.K_LEFT, pygame.K_a) and direction != (1, 0):
    direction = (-1, 0)
elif event.key in (pygame.K_RIGHT, pygame.K_d) and direction != (-1, 0):
    direction = (1, 0)

这个小判断看起来不起眼,但它是贪吃蛇里非常典型的边界问题。

5. 移动、吃食物和碰撞

游戏每一帧都会计算新的蛇头位置,然后判断是否撞墙、撞自己、吃到食物。

head_x, head_y = snake[0]
dx, dy = direction
new_head = (head_x + dx, head_y + dy)

hit_wall = new_head[0] < 0 or new_head[0] >= COLS or new_head[1] < 0 or new_head[1] >= ROWS
hit_self = new_head in snake

if hit_wall or hit_self:
    game_over = True
else:
    snake.insert(0, new_head)
    if new_head == food:
        score += 1
        food = random_food(snake)
    else:
        snake.pop()

Seed Evolving 给我的建议是:先把“死亡判断”放在前面,只有没死才更新蛇身。这样逻辑更清楚。

五、实测效果

运行后会出现一个深色背景的贪吃蛇窗口:

  • 方向键或 WASD 控制移动。
  • 吃到红色食物后加分。
  • 撞墙或撞到自己后显示 Game Over。
  • 游戏结束后按 R 可以重新开始。

在这里插入图片描述

在这里插入图片描述

六、Seed Evolving 具体帮了什么

这次我感觉 Seed Evolving 对小游戏开发的帮助主要在 4 个地方。

1. 把需求拆成可实现模块

一开始只是“做个贪吃蛇”,但 Seed Evolving 把它拆成窗口、蛇、食物、方向、碰撞、分数、重开几个模块。这个拆解让代码不会乱。

2. 提醒我处理经典边界

比如:

  • 食物不能生成在蛇身上。
  • 不能直接反向移动。
  • 撞墙和撞自己都要 Game Over。
  • 游戏结束后要能重开。

这些都是小游戏里很容易漏掉的小细节。

3. 让代码适合新手阅读

我让 Seed Evolving 不要把代码写得太炫技,而是拆成几个函数:

random_food()
draw_grid()
draw_block()
reset_game()
main()

这样每个函数只做一件事,后面想改速度、颜色、窗口大小都比较方便。

4. 帮我保留后续扩展空间

这个版本是基础版,但后续可以继续扩展:

  • 加开始菜单。
  • 加难度选择。
  • 加最高分记录。
  • 加音效。
  • 加障碍物模式。
  • 加暂停功能。

这也是我喜欢用 Seed Evolving 做小项目的原因:它不只是补全代码,还会帮你把下一步能怎么迭代想清楚。

七、踩坑记录

1. Pygame 坐标和格子坐标不要混用

一开始最容易混的是像素坐标和格子坐标。后来我按 Seed Evolving 的建议统一用格子坐标保存状态,绘制时再转换成像素,代码就清楚很多。

2. 反向移动一定要限制

如果不限制反向移动,蛇向右走时按左键会直接撞到自己,游戏体验很怪。

3. 食物不能刷在蛇身上

这个问题肉眼不一定马上发现,但玩几轮就会遇到。所以 random_food() 里必须判断食物位置不在蛇身列表里。

4. Game Over 后不要继续更新蛇身

游戏结束后只负责等待退出或重开,不继续移动蛇,否则画面状态会越来越乱。

总结

这次用 Seed Evolving 做贪吃蛇,最大的感受是:它很适合帮我把一个小想法变成一个完整项目。

它不是只生成一段代码,而是参与了整个过程:

  • 拆需求。
  • 设计数据结构。
  • 提醒边界情况。
  • 生成核心代码。
  • 保留后续扩展方向。

贪吃蛇本身不复杂,但很适合练习“如何把一个小游戏做完整”。从这个角度看,Seed Evolving 像是一个会陪你把小项目一点点搭起来的编程助手。

下一期如果继续做小游戏,我想试试用 Seed Evolving 做一个带关卡和道具的小游戏。

附:完整代码

import random
import sys

import pygame


CELL_SIZE = 24
COLS = 24
ROWS = 20
WIDTH = CELL_SIZE * COLS
HEIGHT = CELL_SIZE * ROWS
FPS = 10

BG_COLOR = (18, 24, 38)
GRID_COLOR = (30, 39, 58)
SNAKE_COLOR = (68, 199, 123)
SNAKE_HEAD_COLOR = (110, 231, 183)
FOOD_COLOR = (248, 113, 113)
TEXT_COLOR = (226, 232, 240)


def random_food(snake):
    while True:
        pos = (random.randint(0, COLS - 1), random.randint(0, ROWS - 1))
        if pos not in snake:
            return pos


def draw_grid(screen):
    for x in range(0, WIDTH, CELL_SIZE):
        pygame.draw.line(screen, GRID_COLOR, (x, 0), (x, HEIGHT))
    for y in range(0, HEIGHT, CELL_SIZE):
        pygame.draw.line(screen, GRID_COLOR, (0, y), (WIDTH, y))


def draw_block(screen, pos, color):
    x, y = pos
    rect = pygame.Rect(x * CELL_SIZE + 2, y * CELL_SIZE + 2, CELL_SIZE - 4, CELL_SIZE - 4)
    pygame.draw.rect(screen, color, rect, border_radius=6)


def draw_text(screen, font, text, x, y):
    image = font.render(text, True, TEXT_COLOR)
    screen.blit(image, (x, y))


def reset_game():
    snake = [(COLS // 2, ROWS // 2), (COLS // 2 - 1, ROWS // 2), (COLS // 2 - 2, ROWS // 2)]
    direction = (1, 0)
    food = random_food(snake)
    score = 0
    game_over = False
    return snake, direction, food, score, game_over


def main():
    pygame.init()
    pygame.display.set_caption("Seed Evolving Snake")
    screen = pygame.display.set_mode((WIDTH, HEIGHT + 56))
    clock = pygame.time.Clock()
    font = pygame.font.SysFont("Microsoft YaHei", 22)
    small_font = pygame.font.SysFont("Microsoft YaHei", 18)

    snake, direction, food, score, game_over = reset_game()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r and game_over:
                    snake, direction, food, score, game_over = reset_game()
                elif event.key in (pygame.K_UP, pygame.K_w) and direction != (0, 1):
                    direction = (0, -1)
                elif event.key in (pygame.K_DOWN, pygame.K_s) and direction != (0, -1):
                    direction = (0, 1)
                elif event.key in (pygame.K_LEFT, pygame.K_a) and direction != (1, 0):
                    direction = (-1, 0)
                elif event.key in (pygame.K_RIGHT, pygame.K_d) and direction != (-1, 0):
                    direction = (1, 0)

        if not game_over:
            head_x, head_y = snake[0]
            dx, dy = direction
            new_head = (head_x + dx, head_y + dy)

            hit_wall = new_head[0] < 0 or new_head[0] >= COLS or new_head[1] < 0 or new_head[1] >= ROWS
            hit_self = new_head in snake

            if hit_wall or hit_self:
                game_over = True
            else:
                snake.insert(0, new_head)
                if new_head == food:
                    score += 1
                    food = random_food(snake)
                else:
                    snake.pop()

        screen.fill(BG_COLOR)
        draw_grid(screen)

        draw_block(screen, food, FOOD_COLOR)
        for index, part in enumerate(snake):
            draw_block(screen, part, SNAKE_HEAD_COLOR if index == 0 else SNAKE_COLOR)

        pygame.draw.rect(screen, (15, 23, 42), (0, HEIGHT, WIDTH, 56))
        draw_text(screen, font, f"Score: {score}", 16, HEIGHT + 14)
        draw_text(screen, small_font, "Arrow/WASD move | R restart", WIDTH - 250, HEIGHT + 18)

        if game_over:
            overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            overlay.fill((0, 0, 0, 150))
            screen.blit(overlay, (0, 0))
            draw_text(screen, font, "Game Over", WIDTH // 2 - 58, HEIGHT // 2 - 28)
            draw_text(screen, small_font, "Press R to restart", WIDTH // 2 - 72, HEIGHT // 2 + 8)

        pygame.display.flip()
        clock.tick(FPS)


if __name__ == "__main__":
    main()

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_44273429/article/details/163474985

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--