Python贪吃蛇实战:从零运行到打包exe全流程
如果只允许用一个词来形容运行这个游戏源码后的感受我会选“爽”。它不是 3A 大作也没有任何美术资源就是一段几百行的 Python 代码但你会在里面体会到完整的游戏闭环键盘控制、碰撞检测、食物生成、分数累积、游戏结束。更重要的是这个项目能把“学 Python”变成“玩 Python”从源码阅读到功能扩展每一步都有即时反馈。这篇文章会把整个流程走一遍环境准备、源码结构、运行测试、自动批量验证、打包 exe 可执行文件以及如何顺手接一个本地排行榜 API。不管你是刚装好 Python 的纯新手还是想拿小项目练手的老手都可以按这篇内容完整复现。先给结论这个贪吃蛇项目几乎不挑硬件纯 CPU 就能跑依赖只有一个 pygameWindows、macOS、Linux 都能运行非常适合作 Python 入门后的第一个实战项目。1. 核心能力速览能力项说明项目类型Python 游戏实战练手项目核心玩法贪吃蛇方向控制、吃食物、加速增长、碰撞结束运行环境Python 3.8 及以上第三方依赖仅 pygame可选的 Flask 用于排行榜 API显存/GPU 需求不需要独立显卡纯 CPU 即可支持平台Windows / macOS / Linux启动方式命令行运行 Python 脚本是否支持打包支持通过 PyInstaller 打包为 exe是否支持 API可通过 Flask 扩展本地排行榜接口是否支持批量任务支持通过无界面自动游玩脚本批量统计分数适合人群Python 初学者、想巩固基础语法与面向对象编程的开发者从功能上来看这个项目并不复杂但它覆盖的知识点很全面变量、列表、字典、函数、循环、条件判断、随机数、事件监听、类与对象。对刚学完 Python 基础语法的人来说它是一个把语法转成真实产出的最佳跳板。2. 为什么游戏化练手比刷教程更有效2.1 即时反馈降低放弃概率刷语法题时你往往要等很久才能看到“我能用它做什么”的正反馈。游戏项目的反馈是即时的按下方向键蛇就动吃到食物分数就加撞到墙游戏就结束。这种反馈链能提升代码修改动力。2.2 小代码量覆盖完整流程一个贪吃蛇的主逻辑可以压缩到 150 行以内但它已经把软件开发的完整流程走了一遍状态初始化、输入处理、逻辑更新、碰撞检测、渲染输出。这种“小而全”的结构非常适合作为第一个独立完成的程序。2.3 修改门槛低扩展方向多游戏的核心玩法清晰边界明确很适合做二次开发。你可以加暂停、加障碍、加计分板或者把控制方式改成 AI 自动游玩。每加一个功能都是在练“如何拆解需求、如何改代码、如何调 bug”。2.4 适合拿去演示和分享游戏类的项目能直接跑出可见结果截图、录屏、发给朋友都方便。这种“可以给别人看”的属性对编程学习初期的成就感培养很有帮助。3. 环境准备Python 安装与编辑器配置3.1 检查 Python 是否已经安装先打开终端或命令行工具执行python --version如果输出类似Python 3.10.11说明已经装好。如果提示“python 不是内部或外部命令”说明 Python 还没安装或者没有加入环境变量。Windows 用户也可以试一下py --version3.2 安装 Python推荐去 Python 官网下载安装包安装时务必勾选“Add Python to PATH”这个选项否则后续命令行里找不到 Python。安装完成后重新打开命令行确认版本信息能正常输出再继续下一步。3.3 安装 pygame命令pip install pygame如果你使用的是国内镜像可以加快下载速度pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple3.4 选择编辑器推荐 VS Code 或 PyCharm。VS Code 安装 Python 扩展后可以直接在编辑器里运行脚本也能看到更清晰的错误提示。本文的所有命令都基于命令行用任何编辑器都能复现。3.5 准备项目目录建议单独建一个文件夹比如snake_game后续所有代码和打包文件都放在里面方便管理。mkdir snake_game cd snake_game4. 游戏源码结构与完整代码4.1 项目文件结构snake_game/ ├── snake.py # 主游戏脚本 ├── auto_test.py # 无界面自动游玩测试脚本 ├── server.py # 本地排行榜 API可选 └── dist/ # 打包输出目录4.2 完整可运行代码下面这段代码是 pygame 版贪吃蛇的核心实现。直接保存为snake.pyimport random import sys import pygame # 初始化 pygame pygame.init() # 窗口与网格参数 WIDTH, HEIGHT 600, 600 CELL 20 FPS 10 # 颜色 BLACK (0, 0, 0) GREEN (0, 200, 0) RED (200, 0, 0) WHITE (255, 255, 255) # 窗口与时钟 screen pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption(贪吃蛇Python 实战练手) clock pygame.time.Clock() font pygame.font.Font(None, 36) def generate_food(snake): 生成食物避免出现在蛇身上 while True: food [ random.randint(0, (WIDTH - CELL) // CELL) * CELL, random.randint(0, (HEIGHT - CELL) // CELL) * CELL, ] if food not in snake: return food def draw_snake(snake): for block in snake: pygame.draw.rect(screen, GREEN, (block[0], block[1], CELL, CELL)) def draw_food(food): pygame.draw.rect(screen, RED, (food[0], food[1], CELL, CELL)) def show_score(score): text font.render(fScore: {score}, True, WHITE) screen.blit(text, (10, 10)) def main(): snake [[100, 100], [80, 100], [60, 100]] direction right food generate_food(snake) 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 ! down: direction up elif event.key pygame.K_DOWN and direction ! up: direction down elif event.key pygame.K_LEFT and direction ! right: direction left elif event.key pygame.K_RIGHT and direction ! left: direction right # 移动蛇头 head snake[0].copy() if direction up: head[1] - CELL elif direction down: head[1] CELL elif direction left: head[0] - CELL elif direction right: head[0] CELL # 碰撞检测撞墙或撞自己 if head[0] 0 or head[0] WIDTH or head[1] 0 or head[1] HEIGHT: running False if head in snake: running False snake.insert(0, head) # 吃到食物 if head[0] food[0] and head[1] food[1]: score 1 food generate_food(snake) else: snake.pop() # 渲染 screen.fill(BLACK) draw_snake(snake) draw_food(food) show_score(score) pygame.display.flip() clock.tick(FPS) pygame.quit() print(f游戏结束最终得分{score}) if __name__ __main__: main()4.3 代码关键点拆解4.3.1 蛇的表示方式蛇用二维列表表示每一项是一个[x, y]坐标。蛇头是snake[0]蛇尾是snake[-1]。这种设计让“移动”变得很简单插入新蛇头如果没有吃到食物就移除蛇尾。4.3.2 方向控制逻辑为了防止玩家在同一帧内按两个方向导致蛇反向移动代码里加了方向互斥判断if event.key pygame.K_UP and direction ! down: direction up这样蛇不能直接穿过自己身体往回走。4.3.3 食物生成sleep 函数的generate_food用while True循环确保食物不会生成在蛇身上。对新手来说这种写法值得记下来当需要随机生成一个满足特定条件的数值时轮询检查是简单且可靠的方案。4.3.4 碰撞检测撞墙检测判断的是蛇头坐标是否超出窗口边界。撞自己检测判断的是蛇头是否出现在蛇身列表里。这里有个细节因为蛇头刚被插入snake所以判断顺序是先检测后插入。如果先插入再检测蛇头永远会算作撞到自己导致游戏无法开始。5. 运行游戏与功能测试5.1 启动游戏在项目目录下执行python snake.py正常情况下会弹出一个黑色窗口左上角显示分数一条绿色蛇在画面中移动。5.2 测试用例清单测试项操作预期结果窗口启动执行脚本窗口正常打开蛇开始移动方向控制按上下左右方向键蛇按对应方向移动不能直接反向吃食物控制蛇靠近红色方块食物消失分数 1蛇身变长撞墙结束让蛇头碰触窗口边缘游戏退出命令行输出最终分数撞自己结束让蛇头碰触自身身体游戏退出命令行输出最终分数窗口关闭点击窗口关闭按钮程序正常退出5.3 判定成功的标准以上测试项全部通过说明项目可以稳定运行。重点观察两点方向控制是否流畅、分数是否在吃到食物后正确递增。如果出现闪退、卡顿、按键无响应需要按第九章排查。5.4 第一次修改建议把FPS从 10 改成 15然后重新运行感受游戏速度变化FPS 15这一步能直观理解“帧率”对游戏手感的影响也是第一次改代码的最佳体验。6. 自动游玩与批量统计测试手动玩只能测试单局体验。要做稳定性验证可以写一个无界面自动游玩脚本让蛇自己朝食物走批量跑几十局统计平均得分和最大分数。这是练习“批量任务 日志统计”的好机会。6.1 无界面自动游玩脚本将下面的代码保存为auto_test.pyimport random class SnakeGame: 无界面的贪吃蛇逻辑模拟器 def __init__(self, width30, height30): self.width width self.height height self.snake [[15, 15], [14, 15], [13, 15]] self.direction right self.score 0 self.food self._generate_food() def _generate_food(self): while True: food [ random.randint(0, self.width - 1), random.randint(0, self.height - 1), ] if food not in self.snake: return food def _step(self): head self.snake[0].copy() if self.direction up: head[1] - 1 elif self.direction down: head[1] 1 elif self.direction left: head[0] - 1 elif self.direction right: head[0] 1 # 撞墙或撞自己 if head[0] 0 or head[0] self.width or head[1] 0 or head[1] self.height: return False if head in self.snake: return False self.snake.insert(0, head) if head[0] self.food[0] and head[1] self.food[1]: self.score 1 self.food self._generate_food() else: self.snake.pop() return True def auto_play(self, max_steps1000): 自动朝食物方向移动 for _ in range(max_steps): head self.snake[0] dx self.food[0] - head[0] dy self.food[1] - head[1] if abs(dx) abs(dy): self.direction right if dx 0 else left else: self.direction down if dy 0 else up if not self._step(): break return self.score def run_batch(n50): 批量运行 n 局返回统计结果 scores [] for i in range(n): game SnakeGame() score game.auto_play() scores.append(score) print(f第 {i 1} 局结束得分{score}) if scores: avg_score sum(scores) / len(scores) print(f\n共运行 {n} 局) print(f平均得分{avg_score:.2f}) print(f最高得分{max(scores)}) print(f最低得分{min(scores)}) return scores if __name__ __main__: run_batch(50)运行方式python auto_test.py6.2 批量测试的价值这个脚本不依赖 pygame在命令行就能跑。它把游戏核心逻辑从界面渲染中分离出来方便做自动化验证。你还能把它进一步改造成统计不同参数下的平均得分。测试不同初始方向策略的胜率。用日志文件记录每一局的轨迹方便复盘。这种“把逻辑从界面中抽出来”的思路在后续做算法设计和自动化测试时非常重要。7. 打包为 exe 可执行文件7.1 安装 PyInstallerpip install pyinstaller7.2 基本打包命令pyinstaller -F -w snake.py参数解释-F打包为单个可执行文件。-w运行时不显示命令行窗口。打包完成后可执行文件在dist/snake.exeWindows或dist/snakemacOS/Linux。7.3 保存分数日志的打包方式注意-w会隐藏控制台窗口导致print()输出的分数不可见。如果希望始终保留运行日志可以去掉-wpyinstaller -F snake.py这样游戏结束后命令行窗口里仍然能显示最终得分。7.4 打包后文件过大如果发现 exe 体积偏大这是 PyInstaller 打包 pygame 的正常现象不必担心。pygame 本身包含多项媒体支持打包后体积通常在几十 MB 级别。想减小体积可以尝试压缩可执行文件或用 UPX 压缩但对这个小项目来说体积不是关键问题。7.5 杀毒软件误报Windows 下使用 PyInstaller 打包的 exe 偶发杀毒软件误报。建议在测试环境先运行几款杀毒软件扫描确认或者把打包结果分发给自己信任的人再使用不要直接对外传播不明来源的 exe。8. 接口 API 与 Web 扩展思路贪吃蛇本身不依赖网络。但如果你想把它改造成一个可以展示给朋友的小项目可以给游戏加一个本地排行榜 API。这里用 Flask 实现一个最简单的服务。8.1 安装 Flaskpip install flask8.2 排行榜接口实现保存为server.pyfrom flask import Flask, jsonify, request app Flask(__name__) # 内存排行榜 scores [] app.route(/api/score, methods[POST]) def add_score(): data request.get_json(forceTrue) player data.get(player, anonymous) score data.get(score, 0) scores.append({player: player, score: score}) scores.sort(keylambda x: x[score], reverseTrue) return jsonify({ok: True, count: len(scores)}) app.route(/api/scores, methods[GET]) def list_scores(): return jsonify(scores[:10]) if __name__ __main__: app.run(host127.0.0.1, port5000)启动服务python server.py8.3 调用接口测试新增分数curl -X POST http://127.0.0.1:5000/api/score \ -H Content-Type: application/json \ -d {\player\: \admin\, \score\: 25}查询排行榜curl http://127.0.0.1:5000/api/scores用 Python 的requests调用也一样import requests response requests.post( http://127.0.0.1:5000/api/score, json{player: test_user, score: 18}, timeout5, ) print(response.json())8.4 接口扩展提醒当前接口数据保存在内存里服务重启后数据会丢失。如果要持久化可以把数据写入 JSON 文件或 SQLite。这个扩展思路适合练习 Web API 基础但注意只适合本地测试环境不要直接暴露到公网否则需要加认证和访问限制。9. 常见问题与排查方法问题现象可能原因排查方式解决方案提示python不是内部或外部命令Python 未安装或未加入 PATH执行python --version或py --version重新安装 Python 并勾选 Add Python to PATH提示No module named pygame依赖未安装执行pip show pygame执行pip install pygame运行后窗口闪退代码报错但窗口提前关闭使用命令行运行python snake.py查看报错按报错信息修复代码或依赖方向键控制反向坐标方向理解错误检查方向改变时的坐标加减逻辑y 轴向下增大时up 应减小 y 值蛇一开局就结束蛇头初始位置和方向冲突打印初始蛇列表检查确保初始蛇身坐标沿移动方向排列打包后 exe 无法运行被杀毒软件拦截或模块缺失查看杀毒隔离记录或命令行运行 exe添加信任或重新打包Flask 接口无法访问服务未启动或端口占用执行python server.py检查终端输出切换端口或关闭占用程序自动游玩脚本得分一直为 0自动方向策略陷入死循环打印每步方向与位置增加随机避障逻辑或调整方向策略10. 最佳实践与学习建议10.1 第一次先跑通不要急着加功能先把原版代码运行起来确认每一行代码的作用再开始修改。新手最忌讳一边运行一边大改出了问题无法判断是哪一步引入的。10.2 用 Git 保存每次修改给项目初始化 Git 仓库每完成一个功能提交一次。这样能清楚地看到每次改动的影响范围也能随时回退到可运行版本。10.3 把界面和逻辑分离在自动游玩脚本里我特意把游戏逻辑写成独立类。这个设计不仅是自动化测试的基础也是后续扩展的核心。建议你在个人项目里尽量把“业务逻辑”和“展示层”分开。10.4 合理管理素材和源码目录如果后续加入音效、图片、字体等资源建议统一放到assets目录并把所有资源路径用相对路径管理snake_game/ ├── assets/ │ ├── sounds/ │ └── images/ ├── src/ │ ├── game.py │ └── auto_test.py └── README.md10.5 批量任务一定要加日志自动游玩脚本输出了每一局的分数并在最后汇总统计。真正处理批量任务时哪怕只是批量测试也要保留每一轮的结果否则后期很难定位问题。10.6 接口服务要控制访问范围排行榜 API 只监听127.0.0.1意味着只能本机访问。想给朋友展示时可以改成0.0.0.0但必须考虑认证和网络安全风险。对外暴露接口前建议先确认不会泄露敏感信息。10.7 发布和分发前做好效果复核如果想把这个项目发布到博客或开源平台记得检查源码里是否有临时路径、本机用户名、自定义配置等隐私信息。打包的 exe 也需要测试不同 Windows 版本下的兼容性。11. 总结与下一步这个贪吃蛇项目最值得尝试的点是它把 Python 基础语法变成了一个能玩、能改、能分享的完整作品。从运行原版、修改参数、自动测试、打包 exe 到接一个简单 API整个过程能覆盖大部分 Python 初学者应该掌握的核心技能。第一次动手建议先完成三条线运行原版游戏把每个函数的作用读一遍尤其是方向控制和碰撞检测。写一个自动游玩脚本跑 50 局批量统计分数验证逻辑稳定性。把游戏打包成 exe发给身边朋友试玩收集反馈。最容易踩的坑有三个一是方向控制里忘记做反向限制二是碰撞检测的顺序写错三是刚装好 pygame 就急着写复杂功能但没先跑通最小版本。这三个问题在本文对应章节都给出了排查思路遇到时可以直接对照解决。后续扩展方向可以继续做给游戏加障碍物和关卡系统、尝试用 AI 算法让蛇自动寻路、把排行榜数据接入 SQLite 持久化、给游戏增加音效和背景音乐。每一步都是在不同维度上提升你的 Python 工程能力。建议先把这篇内容里四个脚本完整跑通一遍再挑选一个方向深入改。