ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python小游戏毕业设计:pygame吃豆人完整实现攻略

Python小游戏毕业设计:pygame吃豆人完整实现攻略 毕业设计安排下来的时候很多人第一反应是“写个网页管理系统”或者“做个图书借阅”这种老掉牙项目。说实话这类题目不是不行但答辩时老师听得都想打瞌睡。我去年做的是python小游戏设计最后敲定用吃豆人这个经典街机玩法作为毕业设计课题。今天把整个项目的思路、代码结构、踩过的坑、答辩要点全部写完希望能给准备做游戏类毕设的同学一条明确的路。我选这个题目不是图它简单而是吃豆人在游戏设计里几乎能涵盖所有基础知识点二维地图建模、角色移动逻辑、碰撞检测、AI算法、音效与状态切换、关卡难度递增。这些内容拆开讲每一个都能在答辩时撑起几分钟的硬核问答完全不用担心老师问不出问题或者你答不上来。1.1 核心需求拆分一个小游戏毕设应该包含哪些模块做毕设最忌讳拿到题目就打开编辑器写代码。吃豆人看起来简单但如果不动脑子直接写第一版代码写到一半你就会发现逻辑乱成一团。我当时先花了一个晚上做需求拆分把整个项目分成五个模块地图模块负责迷宫数据的存储、渲染、碰撞判定。这是整个游戏的地基地图设计得好不好直接决定后面角色移动和AI算法写的顺不顺手。角色模块包括玩家控制的吃豆人和四个AI控制的幽灵。角色模块需要处理移动、转向、状态切换。AI逻辑模块这是吃豆人的灵魂也是答辩时最容易出彩的地方。四个幽灵各自有不同的追逐算法效果做出来后能让老师眼前一亮。游戏系统模块计分、生命、关卡切换、胜利/失败判定这些是游戏完整性的保障。渲染与交互模块用pygame或其它库处理窗口绘制、键盘监听、显示刷新。这么一拆代码结构自然清晰了后面每写一块都有方向。最重要的是毕业论文的目录结构可以跟着模块走需求分析、系统设计、模块实现、系统测试这四章内容直接有血有肉。1.2 技术选型为什么是pygame而不是其他方案毕设技术选型要考虑三件事开发效率、问题排查难度、答辩时能不能讲清楚。市面上做Python游戏无非几个选择pygame、tkinter自带的Canvas、甚至直接上PyQt。tkinter虽然不需要装额外依赖但它的游戏开发体验太差了帧率控制、精灵动画、音频播放都要自己从头写简单说就是“能跑但很费劲”。PyQt倒是支持更多交互但它本质是GUI框架拿来写游戏属于杀鸡用牛刀而且打包出来的程序体积大答辩演示时加载都慢。pygame是专门为2D游戏设计的库精灵类、碰撞检测、时钟控制全都内置好了网上资料多遇到问题一搜就有答案。我当时选的版本是Python 3.8配合pygame 2.0.1用了一年非常稳定没有遇到兼容性爆炸的问题。当然有同学可能装了Python 3.11以上的版本pygame的安装方式会有一点变化这个后面我会具体讲到。另外有人会问做吃豆人这类游戏是不是一定要上精灵动画如果你追求画面效果当然可以用精灵表做动画帧切换但毕设项目最核心的是逻辑我用的是简单的几何图形绘制加颜色区分比如黄色圆形当吃豆人、红色圆形当幽灵画面照样能看而且所有精力都花在功能逻辑上这是性价比最高的路径。1.3 功能清单什么样的吃豆人才算“完整”我在写开题报告的时候把功能列得很细每一项目标都是可以验收的玩家控制吃豆人在迷宫中移动遇到墙壁无法穿过地图上散布豆子吃豆人吃掉豆子后分数增加豆子消失设置四个幽灵各自有不同的追踪策略地图中有特殊能量豆吃掉后一段时间内幽灵变为可被反吃状态玩家撞到非虚弱状态的幽灵则减少一条生命生命为零游戏结束全部豆子被吃掉后通关进入下一关关卡难度递增幽灵速度加快、能量豆效果缩短界面显示当前分数、剩余生命、当前关卡编号这七条写出来功能够撑起一个完整的演示。你仔细看每一条其实对应一个或者两个技术难点答辩时老师随便挑一条问你都有话可说。2. 核心系统设计与数据建模2.1 迷宫地图的数据结构用数组铺出整个游戏世界吃豆人的迷宫在逻辑上就是一个网格世界最直观的存储方式就是二维数组。我用的是一个纯文本文件定义地图每一行字符串代表迷宫的一行每个字符代表一种格子类型这让地图修改非常方便后续想加关卡只需要新增一个文本文件完全不需要动代码。我定义的地图字符映射关系如下字符含义备注X墙体不可通行碰撞判定.普通豆子吃到加10分O能量豆吃到加50分幽灵虚弱-空地可通行无道具P玩家出生点地图中有且仅有一个G幽灵出生点四个幽灵的初始位置下面给一个迷你示例地图我毕设实际用的是28列乘以31行的标准地图这里为了方便讲解缩短了尺寸XXXXXXXXXXXXXXXX X....XX....XX..X XOXX.X....X.XXOX X....XX....XX..X XXXXXXXXXXXXXXXX每一行字符长度必须一致不然渲染时会错位。我的代码里加了一个校验函数加载地图时如果发现行长度不一致直接报错并指出第几行这个设计在调试阶段救了我无数次。实际渲染的时候墙体的颜色用深蓝色豆子是浅黄色小圆点能量豆用更大的闪烁圆点。你可能会问地图数据只有字符怎么和像素坐标对应这就要讲到格子大小和坐标换算了。我定义每个格子的大小GRID_SIZE为20像素那么第row行第col列的格子的左上角像素坐标就是(col * GRID_SIZE, row * GRID_SIZE)。角色移动时也是以格子为单位判断同一个格子内坐标缺失的精度问题就完全绕开了。2.2 角色实体设计Pacman类和Ghost类的抽象写到这里我建议你把游戏里的角色都抽象成类。这不是为了炫技而是因为吃豆人和幽灵有很多共同属性坐标、方向、速度、存活状态。我用一个基类Role保存这些公共属性然后Pacman和Ghost分别继承并扩展各自的独有逻辑。Role基类大致长这样class Role: def __init__(self, row, col, speed): self.row row self.col col self.speed speed self.direction left self.next_direction left def can_move(self, direction, maze): # 计算目标格子的行列 target_row self.row target_col self.col if direction up: target_row - 1 elif direction down: target_row 1 elif direction left: target_col - 1 elif direction right: target_col 1 return maze[target_row][target_col] ! X这里有个关键细节角色移动我用的是“整格跳转”而非“平滑移动”每个逻辑帧检查一次当前方向能不能走能走就移动到下一格中心。这个设计让碰撞检测变得异常简单因为角色永远落在整数格子坐标上不需要处理像素级的碰撞。如果非要像素级的平滑动画可以在此基础上做中间插值渲染但逻辑判定仍然走格子坐标。Pacman类额外需要记录分数、剩余生命还有一个“正在吃的动画计数”。Ghost类则多了AI状态机当前状态可以是chase追击、scatter散开、frightened虚弱或者eyes回巢这个我在2.3会详细展开。2.3 幽灵AI四个不同的追逐算法才是亮点说实话很多网上的吃豆人代码把四个幽灵写成一个逻辑追玩家的方式一模一样。这就像四个人跑步只有一种跑法失去了灵魂。经典吃豆人每个幽灵都有独特的性格设定这也是项目答辩最加分的点。我当时复刻了四个经典算法你可以直接拿去用红色幽灵追击者。逻辑最简单也最凶每帧都朝着玩家当前所在的格子移动。因为触发频率太高它几乎不会迷茫永远直奔目标是新手最容易碰到的威胁。粉色幽灵预判者。它追的不是玩家当前位置而是玩家预计会去的位置我让它在更新目标格子时取玩家前方四个格子。这样当你在一条直道狂奔时粉色幽灵不会傻傻跟在你屁股后头而是直接在你前方等着劫道压迫感直接拉满。蓝色幽灵围堵者。它不单纯追目标而是计算“玩家当前位置”和“红色幽灵当前位置”的连线然后取这条线延长一倍后的点作为目标。效果是玩家往哪跑蓝色幽灵就跑到玩家前侧方形成包围。这个逻辑最花心思但也最容易讲清楚。下面给一个简化的函数说明蓝幽灵怎么计算目标点def get_inky_target(player_pos, red_pos): # 向量运算从红色幽灵指向玩家然后延长一倍 delta_x player_pos[0] - red_pos[0] delta_y player_pos[1] - red_pos[1] target_x player_pos[0] delta_x target_y player_pos[1] delta_y return target_x, target_y橙色幽灵犹豫者。追玩家时先算距离如果距离大于8格就追小于等于8格就随机游走。它的行为最不规律会给玩家制造意外风险。四个幽灵还有一个散开模式在游戏开始阶段或者玩家刚吃完能量豆后的一段时间里它们各自散开到地图四角不会一窝蜂涌向玩家。实现方式是在状态机里加一个定时切换逻辑每7秒在追击和散开两个模式间切换一次。这种设计让幽灵的AI有了层次感既不会太难也不会太简单。关于路径选择幽灵每次到交叉路口都要决定往哪走。我用的是离目标点曼哈顿距离最小的方向优先策略同时加上一个限制不能走回头路。这样幽灵看起来就非常智能像真的在围剿玩家。2.4 能量豆机制状态切换与角色反转能量豆的实现并不复杂核心就是一个状态计时问题。我定义了一个全局状态当前是否处于“虚弱期”还有多少帧结束。玩家吃到能量豆后计时器设为400帧也就是大约6.6秒按60FPS算这段时间内幽灵全部变成蓝色速度降低为原来的70%并且方向行为变成随机游走不与玩家主动碰撞。有点意思的是当虚弱期快结束时画面上的幽灵图标在最后三秒会闪烁变白提示玩家“我要恢复原状了快别碰到我”。这个闪烁效果我用了简单的时间取模判断每10帧切换一次颜色完全不需要额外状态机。吃鬼判定就一句话当玩家格子坐标与幽灵格子坐标相同时如果幽灵处于虚弱状态则幽灵被吃分数加200幽灵变成一双眼睛的图像快速自动导航回出生点如果幽灵处于正常状态则玩家损失一条命然后回到出生点重置。蓝幽灵被打回出生点后因为中途改变状态涉及原位置这里要注意把幽灵的AI状态重置为chase否则它出来还是一副可怕的样子。3. 实操实现从空文件到可玩版本3.1 环境搭建pygame安装与初始化细节写代码之前先把环境准备好。如果你的电脑还没有Python去官网下载对应版本记得安装时勾选Add Python to PATH这一步不勾后面命令行里访问不到python命令会莫名浪费半小时。装好后打开终端python --version pip --version看到版本号之后安装pygame。这是我实际用的一条命令加了清华镜像源速度比默认源快很多pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple如果安装过程中看到类似的报错大概率是版本兼容问题ERROR: Could not find a version that satisfies the requirement pygame这种情况一般有两个原因一是Python版本太老或太新pygame支持跟不上二是pip本身版本太旧。先执行python -m pip install --upgrade pip升级一下再重新安装。如果还是不行可以去官网下载对应系统的whl文件用pip离线安装。初始化pygame有固定套路我把它封装在一个init函数里import pygame pygame.init() screen pygame.display.set_mode((560, 620)) # 地图宽28格*20 计分栏高度 pygame.display.set_caption(Pacman Designed by YourName) clock pygame.time.Clock()这里窗口宽高的计算是有讲究的地图28列乘以20像素等于560像素地图31行乘以20等于620像素还额外留了显示分数的条带区域。如果你自己设计关卡窗口大小要跟着地图尺寸走否则画面会溢出或者留白。3.2 游戏主循环输入、更新、渲染的黄金三步pygame游戏本质上就是一个死循环循环里每次迭代做三件事监听并处理用户输入、更新所有游戏对象的状态、把画面绘制到屏幕上。我用一个核心循环来驱动整个游戏骨架大致如下while running: for event in pygame.event.get(): if event.type pygame.QUIT: running False elif event.type pygame.KEYDOWN: # 记录玩家想转向的方向到next_direction if event.key pygame.K_UP: pacman.next_direction up # ...省略其他方向键处理 # 更新阶段 pacman.update(maze) for ghost in ghosts: ghost.update(player_postuple(pacman.get_pos()), mazemaze) # 碰撞检测与得分处理 check_eat_dot(pacman, maze) check_eat_ghost(pacman, ghosts) # 渲染阶段 maze.render(screen) pacman.render(screen) for ghost in ghosts: ghost.render(screen) render_score(screen) clock.tick(60) # 锁定帧率在60FPS这里有个血泪教训如果你不调用clock.tick(60)游戏会跑得飞快吃豆人快到根本看不清幽灵的AI更新频率也会失控。而如果帧率太低玩家操作会有明显延迟。60帧是最合理的数值。键盘输入为什么监听KEYDOWN而不是监听KEYUP因为吃豆人要记录的是“下一步转向意图”而不是持续按住。举个例子你正在往左走前方一格就是墙壁不能掉头但你按了向上的方向键这时候应该把意图方向存到next_direction里等吃到豆人走到格子交叉口并且能向上走时再执行转向。这个缓冲机制如果没有手速稍快按早了就绝无可能在路口转弯游戏体验会大打折扣。3.3 移动与碰撞检测为什么我的吃豆人不会穿墙碰撞检测在格子坐标系下简单到令人难以置信。你不需要判断两个矩形是否相交只需要检查一个目标格子是否等于墙体字符。def check_collision(row, col, maze): return maze[row][col] X吃豆人每次移动前先计算下一步的位置调用上面的函数判断目标格子是否可通行。如果是墙就留在原地并且清空当前方向的移动意图。这里有个细节值得注意在交叉路口角色应当优先尝试玩家新按的方向如果新方向不能走再尝试原来方向。这个优先级顺序直接影响操作手感。我实际调试时发现如果在转弯处检测到新方向不能走就直接停住玩家会觉得很卡。后来改成“新方向不能走旧方向如果能走就继续走”整个手感的流畅度上了一个台阶。这也是答辩时你可以拿出来讲的优化点之一。豆子碰撞检测也走格子坐标玩家到达某个格子后检查地图数据中该格子是普通豆子还是能量豆是豆子则分数增加并把对应格子改成空地。这个逻辑因为每次操作量极小完全不会拖慢游戏速度。3.4 计分、生命与过关判定让游戏真正“可结束”一个游戏程序如果没有结束条件那只能算交互演示不能称为完整作品。我的结束判定分三种玩家死亡、通关、主动退出。玩家与幽灵碰撞时先判断幽灵状态如果幽灵是虚弱状态则幽灵被吃否则玩家生命减1生命归零则游戏结束并显示Game Over如果玩家吃掉了地图上所有豆子则显示“恭喜过关”并加载下一关地图下一关幽灵速度整体提升10%能量豆的虚弱持续时间缩短10%。关卡切换我写了一个read_next_level函数它会读取预置好的level2.txt、level3.txt如果读到最后一关就循环回第一关但速度继续增加这样游戏理论上可以无限玩下去难度越来越高。还有一个特别容易忽略的细节吃完豆子加分后渲染阶段必须重新绘制整个区域的画面。如果不重新绘制画面上的豆子可能还存在玩家视觉里你以为没吃到但其实分已经加了。我踩过这个坑后干脆在每次操作之后全屏重绘一个像素都不落下虽然无脑但绝对不会出现显示和数据不同步的问题。3.5 音效资源与字体处理的实用技巧毕设虽然有音效更能加分但我不建议你花太多时间找音乐素材。我用的是一个简单到极致的方法调用pygame自带的mixer播放短音频。网上有很多免费的游戏音效素材站下载一声“吃东西”的短音效、一声“被撞死”的音效再找一首轻快的循环BGM就够了。这里有一个中文玩家老遇到的头疼事pygame默认字体不支持中文如果你用pygame.font.SysFont(SimHei, 24)在Win上能显示但在Linux或者Mac上就可能显示成一个个方块。我后来妥协了界面文字全部用英文Pacman、Score、Life反而显得更像原版街机风格答辩时没有产生任何影响。如果你坚持要做中文界面记得把中文字体文件打包一起带上用pygame.font.Font直接加载ttf文件路径这是最稳妥的做法。4. 常见问题与排查技巧实录踩坑一年总结4.1 安装与运行环境的那些问题先给一份问题速查表都是我在自己开发过程和帮同学调试时遇见过的高频问题问题现象原因解决方案pygame安装报错且速度极慢默认源下载慢或版本冲突用清华镜像源先升级pip再安装运行窗口一闪而过代码直接在窗口创建后退出确认主循环没有被正确进入检查python文件的最后是否调用了game.run()画面闪烁严重没有全屏背景重绘或者用了screen.update()而非flip使用screen.fill(black)后逐元素绘制再调用pygame.display.flip()键盘没有反应监听KEYUP而不是KEYDOWN或窗口没有焦点确保监听KEYDOWN事件并点击窗口让它获得焦点后操作程序跑得飞快缺少帧率控制主循环末尾添加clock.tick(60)CPU占用接近100%主循环没有等待属于帧率失控同上锁帧率后CPU占用大幅下降第四个问题我多说一句。如果你用Pygame写游戏有时键盘事件没反应是因为你在事件循环里用了elif判断但多个按键同时发生时会漏掉部分事件。我的处理是拆成独立的多个if一个按键一个分支独立判断这样同时按多个键也不会吞事件。4.2 角色行为异常的经典Bug案例幽灵穿墙是我调试时最崩溃的一次。现象是幽灵走到一半突然横穿了墙壁看起来像瞬移。排查后发现原因是幽灵在整格移动中某一帧更新了自己的row/col紧接着下一帧在AGGIORNAMENTO渲染时又使用了旧坐标的缓存数据导致画面和逻辑坐标脱节。解决方案是渲染时强制只读取逻辑坐标这个单一数据源绝不同时维护一个“渲染坐标”和一个“逻辑坐标”这是新手最容易写坏的地方。还有一个让人哭笑不得的Bug明明吃到了能量豆幽灵却没有变蓝。原因是状态机里幽灵的frightened状态只作用于渲染层AI逻辑层仍然走chase路径。排查后我意识到必须让AI逻辑也检查这个状态两套分支要统一。此后我给自己定了一条规矩所有状态相关的逻辑渲染层和AI层的分支必须严格同步。4.3 毕业设计答辩与文档写作的注意事项代码能跑只是及格线答辩表现才决定分数高低。我的经验是不仅要会写代码还要会讲代码。老师常问的问题就那么几类你完全可以提前准备“你为什么要选择pygame做这个项目”不要说“因为网上教程多”你要回答pygame的事件驱动模型天生适合游戏开发内置时钟控制保证了帧率稳定精灵模块简化了角色对象的生命周期管理而且Python快速迭代的特性适合课程设计这种两个月周期内的开发项目。“四个幽灵AI算法的复杂度评估”这个问题看起来难其实背好就行。红色幽灵O(1)直接追踪。粉色幽灵需要读取玩家下一格位置也是常数时间。蓝色幽灵做一次向量运算同样是O(1)。四个幽灵每一帧都要计算与目标格的距离并选择移动方向涉及到遍历四个方向的曼哈顿距离所以单个幽灵的单帧复杂度是O(4)即O(1)。整个AI系统每帧的总开销很小所以游戏在60FPS下毫无压力。“做过什么测试如何保证游戏稳定运行”准备一张测试用例表格是很聪明的做法。我列出了功能测试吃豆子、吃能量豆、撞鬼、通关、边界测试在地图边界移动、在出生点复活、性能测试长时间运行游戏观察内存占用。每一条都对应一个截图或日志记录答辩时直接展示测试用例表老师眉头都能舒展几分。文档写作方面核心是把第一章背景与意义和第三章需求分析写到位不要写成一堆空话。比如背景可以写“街机游戏的黄金年代如何塑造了现代游戏交互范式”需求分析要具体到“输入响应时间应小于100毫秒以保证游戏操作的实时反馈”这样的句子一看就是认真做过系统设计的。5. 扩展玩法与个性化方向建议如果你的项目时间还有富余我建议在功能完整的基础上加点自己的创意。我见过有同学加了一个“双人对战”模式一个吃豆人一个幽灵两个玩家在同一键盘上操作画面中间用竖线分开。这个扩展听起来复杂其实只要在Pacman和Ghost的基础上各增加一个独立控制器就能在答辩时作为“创新点”大力展示。另一个性价比很高的扩展是关卡编辑器。用鼠标在窗口上点击就能把空白格子画成墙把豆子画出来保存为自定义地图文件然后游戏直接加载这个新文件。这个功能复用现有的地图加载逻辑代码量不大但演示效果非常直观老师会觉得你的系统有完整的设计闭环。我当时的个人体会是做吃豆人的过程里真正的难点不在于写出来而在于把AI算法调试到“看起来聪明但又不至于让玩家绝望”的平衡点。蓝幽灵的包围策略一开始做得太聪明玩家每次都像撞枪口后来我把它的转向逻辑加了5%的随机概率效果一下子自然了。这种“调校游戏手感”的经验是在文档里学不到的也是做毕设最宝贵的收获。最后再分享一个小技巧所有模块尽量都要写单元测试或者至少是辅助的自测函数。比如地图加载函数至少测一次空行、多余空格、字符非法的情况AI路径选择函数手动构造一个简单地图断言幽灵应该选择的路径。答辩演示时偶尔紧张但测试代码跑一遍稳定性远超直接演示游戏主体能帮你挽回很多印象分。这套吃豆人的完整项目我从设计到答辩用时大约五周每天有效开发时间两到三小时加上写文档和画图在内属于中等偏上的工作量。如果你现在还在纠结毕设题目可以参考这个思路把经典玩法用现代技术重新演绎一遍项目亮点丰富、可控性强、扩展空间够大拿个优秀论文是很有希望的。
返回列表