拓冰建站拓冰建站
首页 / 资讯中心 / 正文

20个Pygame小游戏源码合集:Python游戏开发实战之路

简介这是一套面向Python初学者与Pygame入门者的实战型小游戏学习资源涵盖20款经典可运行项目有效解决理论学习后缺乏动手实践、项目经验不足的问题适用于课程设计、课余拓展及兴趣驱动式编程训练。压缩包共2000个文件主体为1558个Python源码.py与643个编译字节码.pyc辅以388个PNG图像资源、54个WAV音频素材及20个MP3背景音效完整支撑图形渲染、交互响应与音效反馈另有HTML文档、CSS样式表与Markdown说明文件便于理解结构与查阅注释。资源包大小165.68MB目录组织清晰每个游戏独立成模块含完整入口脚本与资源路径配置。目前已有1295人学习下载所有游戏均经作者亲测可在PyCharm中一键运行无需额外环境适配附带基础调试提示与常见报错解决方案是快速掌握事件循环、精灵管理、碰撞检测等Pygame核心机制的优质实践集。 玩pygame也有七八年了从最早照着教程敲贪吃蛇到后来自己写完整的塔防Demo再到现在整理出一份拿到就能跑的20个pygame小游戏源码合集这条路走下来最大的感触是小游戏不是玩具它是把Python语法、面向对象设计、事件驱动模型一次性串起来的最佳训练场。这篇文章里的所有源码我都逐一在干净环境里跑过能保证正常开窗口、正常响应键盘鼠标、正常退出不报错。不管你是刚学完基础语法想找个练手方向的新手还是想快速给某个活动、课堂、开源项目配几个摸鱼小游戏的开发者这份清单都能让你少踩很多坑。标题里写了爆款我理解这个词不是指游戏本身有多惊艳而是指它们对学习者的性价比极高——每个游戏代码量集中在100到600行之间恰好覆盖一个独立知识点又不会长到让人失去耐心。下面我会把这20个游戏按玩法分类拆开讲清楚它们各自练了什么、运行前要注意什么、拿到源码后怎么改造成自己的版本。1. 先说说这份合集是怎么攒出来的从复现到内化的学习路径最早接触pygame是在一个技术社群里有人分享了一个用pygame做的飞机大战代码只有两百多行但那种用Python控制窗口里每一帧画面的感觉跟写命令行脚本完全是两回事。后来我陆续收集、复现、修改了上百个小游戏最终筛选出这20个标准有三条代码能独立运行、依赖只有pygame和Python标准库、玩法逻辑清晰适合二次开发。1.1 为什么是pygame而不是其他游戏框架市面上Python游戏方案很多比如cocos2d、Panda3D、Arcade但pygame有一个不可替代的优势它足够底层。pygame没有帮你封装好游戏对象、碰撞检测、动画状态机这些高级概念而是直接给你surface画布、rect矩形区域、event事件队列这些基础积木。这意味着你写贪吃蛇时蛇身的移动、食物的生成、撞墙的判断每一步都是自己用代码搭出来的而不是调一个现成的精灵组件。这个从零搭建的过程恰恰是学习的关键。等你把游戏逻辑写明白了再去学那些封装好的游戏引擎反而事半功倍。我见过不少直接上引擎的人遇到性能问题根本不知道该怎么排查因为引擎把底层细节全藏起来了。1.2 20个游戏覆盖的pygame知识点地图整理这20个游戏时我是按知识点覆盖来选的而不是按游戏好不好玩。大致可以分成这么几类分类游戏核心知识点基础窗口类猜数字、时钟显示、随机点阵窗口初始化、文字渲染、游戏主循环碰撞反应类打砖块、乒乓球、飞机大战rect碰撞检测、运动方向反转、分组管理网格棋盘类贪吃蛇、俄罗斯方块、扫雷、2048、五子棋二维数组建模、网格坐标换算、状态机路径寻路类迷宫、推箱子递归回溯、方向试探、地图文件解析反应操作类打地鼠、接水果、弹跳球鼠标事件、计时器、随机生成策略博弈类井字棋、记忆翻牌、猜数字人机交互逻辑、分数系统、回合转换每款游戏都刻意避免与其他游戏在技术上重复度过高。比如同样是操作方块贪吃蛇练的是整个身体跟随头部移动的链表思维俄罗斯方块练的是方块的旋转矩阵变换两者代码写法完全不同。这样你玩通整份合集基本就把pygame的常用API摸了一遍。2. 源码真的能跑起来吗环境搭建与版本兼容的硬经验亲测可运行这句话看起来简单实际做起来挺折腾人的。pygame对Python版本、pip安装源、系统图形接口都有一定要求很多人下载了源码却跑不起来九成不是代码的问题而是环境没配好。2.1 推荐版本组合Python 3.8到3.11配pygame 2.x我测试这20份源码时使用了Python 3.10和pygame 2.5.2的组合全程没有遇到兼容性问题。pygame从2.0版本开始对Python 3.8以上的支持已经非常成熟没必要用Python 3.7以下的旧版本否则部分新语法比如f-string的调试写法、海象运算符会直接报语法错误。如果你用的是Python 3.12我建议先装pygame试运行有个别机器会因为C扩展编译链的问题安装失败这时换个思路用别人打包好的wheel版本或者直接降级到3.10/3.11更省心。好在这些源码里用到的pygame API都是2.x持续推进的稳定功能不存在旧代码跑在新库上崩掉的情况。2.2 安装pygame时最常见的三个坎第一个坎是pip默认源下载速度慢甚至超时。国内环境下建议加上清华镜像参数pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple第二个坎是缺少SDL依赖。pygame底层是SDL库Windows下pip会自动带上对应动态链接库但有些精简版Linux系统或macOS 12以上版本可能会出现安装成功但import时找不到库的情况。这时候需要装系统级依赖# Ubuntu/Debian sudo apt install libsdl2-2.0-0 libsdl2-image-2.0-0 libsdl2-mixer-2.0-0 libsdl2-ttf-2.0-0 # macOS brew install sdl2 sdl2_image sdl2_mixer sdl2_ttf第三个坎是Python 3.12下装pygame 2.5.2找不到wheel。这个我在一台Ubuntu服务器上遇到过报错信息类似Getting requirements to build wheel ... did not run successfully。很多新手看到这串英文就慌了其实解决办法很直接# 先升级pip再试 python -m pip install --upgrade pip setuptools wheel # 还不行就明确指定版本 pip install pygame2.5.22.3 源码目录里的资源和路径问题很多小游戏不是单一py文件而是带一个文件夹存放图片、音效。这类游戏如果直接从压缩包里双击运行容易出现找不到素材文件的报错。我的处理方法是统一约定所有素材路径都使用相对路径并且规定从源码根目录启动。比如打砖块游戏里的音效文件代码写的是sound pygame.mixer.Sound(sounds/hit.wav)这个路径只在当前工作目录是源码根目录时有效。如果你在IDE里直接按F5运行而IDE的工作目录设置成了编辑器的临时目录就会报错。最好在项目根目录建一个运行脚本或者用下面这段代码规范工作目录import os, sys os.chdir(os.path.dirname(os.path.abspath(__file__)))放在所有import和资源加载之前能解决九成路径问题。3. 拆解第一波弹球与射击类游戏的核心逻辑我在整理源码时发现弹球类和射击类是最适合新手入门的因为它们核心就一句话每一帧更新物体的坐标然后判断是否撞到边界或其他物体。把这句话落地成代码你就理解了游戏循环的本质。3.1 打砖块碰撞反弹的方向反转是核心难点打砖块的代码量一般在300行上下方块、挡板、小球三个对象加上计分和关卡重置。新手最容易卡住的地方是小球撞到挡板后的反弹角度。很多初版代码只做这样简单的反转if ball.colliderect(paddle): ball.speed_y -ball.speed_y这样写的问题在于不管小球撞到挡板左边还是右边反弹角度都一样玩起来非常死板。改进方法是根据撞击位置偏移量计算反弹角度if ball.colliderect(paddle): relative_x (ball.centerx - paddle.left) / paddle.width # 0~1 angle (relative_x - 0.5) * 2 * 60 # -60度到60度 ball.angle_deg angle把角度从简单反转改成入射点到挡板中心的偏移比例游戏手感立刻不一样。这个思路在很多街机游戏里都能用上属于一次学会到处复用的技巧。源码里我用的就是偏移算法你拿到后可以调大调小60这个系数感受下不同手感。3.2 飞机大战子弹管理比飞机本身更重要飞机大战的代码结构很典型玩家飞机类、敌机类、子弹类通过pygame的sprite.Group管理多个实例。新手写这类游戏时经常犯一个错误——无限生成子弹导致内存和性能爆炸。源码里我实现了一个对象池思路维护一个子弹列表每次发射时先检查列表里的子弹是否超出屏幕超出就直接移除或复用而不是不断创建新对象。核心代码类似class Bullet(pygame.sprite.Sprite): def update(self): self.rect.y - self.speed if self.rect.bottom 0: self.kill() # 超出屏幕自动销毁 bullets pygame.sprite.Group() bullets.update() # 每帧调用一次自动清理超出边界的子弹很多做了多年游戏开发的人可能觉得这不值一提但对新手来说这恰恰是可正常运行和运行一会儿就卡死的分水岭。这20个游戏源码里所有涉及大量物体生成的游戏都采用了Group和kill机制保证长时间运行内存不涨。3.3 乒乓球的AI对手怎么让电脑显得很强但又会失误乒乓球Pong是个有意思的小游戏它练的是键盘控制和简单AI。双人模式好写两个玩家各自控制挡板上下移动即可但单人模式需要一个电脑对手写不好就会显得要么蠢到家、要么强到无敌。我采用的方案是给电脑挡板设置一个反应速度上限电脑挡板不是直接对准球的y坐标移动而是每帧只允许移动一段最大距离。这样当球速很快时电脑会来不及精确跟防偶尔漏球看起来就像真人玩家一样有失误。ai_speed 3 target_y ball.rect.centery - ai_paddle.rect.height // 2 if ai_paddle.rect.centery target_y - 10: ai_paddle.rect.y ai_speed elif ai_paddle.rect.centery target_y 10: ai_paddle.rect.y - ai_speed这个故意留误差区间的思路特别值得记下来以后写任何包含AI的游戏都用得上。源码里我给留了参数调节的地方把10改大电脑就变笨改小电脑就变准。4. 拆解第二波网格棋盘类游戏的二维思维如果说弹球类练的是物体的物理运动那网格棋盘类练的就是数据的抽象建模。贪吃蛇、俄罗斯方块、扫雷、2048、五子棋这五个游戏的共同特征是屏幕上的每一个图形元素背后都对应着二维数组里的一个格子。4.1 贪吃蛇用列表模拟整条蛇的身体贪吃蛇看起来简单但核心数据结构很有意思。蛇的身体可以用一个列表存储列表的每个元素是蛇身一节的坐标。每移动一步新的头部坐标插入列表最前面如果没吃到食物就把尾部弹出去snake_body [(5, 5), (5, 4), (5, 3)] # 初始三节头部在前 def move(direction): head_x, head_y snake_body[0] dx, dy direction new_head (head_x dx, head_y dy) # 吃到食物就不弹出尾部身体变长 if new_head food_pos: snake_body.insert(0, new_head) else: snake_body.insert(0, new_head) snake_body.pop()这个模型非常直观而且自然实现了蛇身跟随头部移动的效果。新手学这个游戏的最大价值就在于理解数据结构和画面表现之间的关系——你在代码里操作的是一串坐标元组投影到屏幕上是就是一条游动的蛇。4.2 俄罗斯方块矩阵旋转是数学问题不是游戏问题俄罗斯方块比贪吃蛇高一个台阶难点在于方块的旋转。每个方块可以用一个4x4或3x3的矩阵表示其中的1代表有方块0代表空白。旋转操作本质上是对矩阵做转置加行翻转def rotate(matrix): # 顺时针旋转90度 return [list(row) for row in zip(*matrix[::-1])]我见过很多人实现旋转时会用一堆if判断来硬编码每个方向的形状代码又长又容易错。用矩阵运算一行搞定思路也清晰。源码里还处理了几个旋转时容易出bug的细节旋转后可能会超出边界或卡进已有方块里所以需要先做能否旋转的检测如果旋转后会碰撞就不执行旋转。4.3 2048和扫雷怎么用二维数组处理游戏状态2048的游戏逻辑全在一个4x4的二维数组里滑动操作可以拆解成提取一行数字、去零、合并、补零这个模式。源码里给每个方向都封装了一个操作函数但底层复用的是同一套向左合并逻辑其他方向通过旋转数组复用来实现。扫雷的难点则是初次点击不能踩雷的保证。实现方式是在第一次点击格子时随机生成地雷分布而不是游戏一开始就生成。这样玩家运气再怎么差第一步也绝对安全。这个设计细节很多新手压根没想到等到自己复现扫雷时才发现开局即死是多么糟糕的体验。网格类游戏最大的练习价值在于你得学会用一行行坐标变换去维护游戏规则的完整性。比如2048合并时2 2 2 2应该变成4 4 0 0而不是0 0 4 4这种细节只有写代码时踩过坑才会印象深刻。5. 拆解第三波鼠标操作与关卡设计类游戏前面的游戏大多靠键盘控制而打地鼠、记忆翻牌、接水果、迷宫、推箱子这类游戏核心操作都在鼠标上技术点也偏向交互反馈和关卡数据组织。5.1 打地鼠如何用计时器控制随机出现与消失打地鼠的难点不是画地鼠而是控制出现节奏和玩家点击的命中判定。源码里我用了两个计时器一个控制地鼠出现在哪个洞另一个控制地鼠在洞里能停留多长时间。用pygame自带的时间戳来做避免用time.sleep因为sleep会卡住整个游戏循环导致画面冻结。now pygame.time.get_ticks() if now - last_spawn_time spawn_interval: spawn_mole() last_spawn_time now for mole in active_moles: if now - mole.born_time mole.lifetime: mole.hide() # 超时自动消失这里有个细节命中判定不能只靠鼠标位置因为玩家点中的是地鼠图片的矩形区域而图片本身可能有透明背景。为了手感更好我用了矩形检测但缩小了有效点击范围——也就是实际判定区域是图片矩形向内缩小20%后的区域。这样玩家点在地鼠旁边一点也能算命中玩起来不会觉得判定太苛刻。5.2 迷宫和推箱子关卡地图用纯文本文件定义这两款游戏在设计上有异曲同工之处关卡本身是一张二维地图用字符表示不同元素。比如迷宫里的字符约定是# 墙壁 . 空地 S 起点 E 终点推箱子则多几种字符 玩家 $ 箱子 . 目标点 * 箱子在目标点上 玩家在目标点上源码里关卡数据都以纯文本字符串的列表形式存放在代码顶部读取后转成二维数组再渲染成图像。这种设计极大方便了添加新关卡——你不需要改任何游戏逻辑只要照着格式添加几个字符串新关卡就自动生成了。我强烈建议新手去读一读推箱子的源码因为地图解析 移动判定 状态刷新这个流程几乎适用于所有关卡制小游戏。理解了它你就掌握了做自定义关卡游戏的万能骨架。5.3 接水果和弹跳球的难度曲线设计这类操作反应类游戏最容易翻车的地方是难度曲线。如果难度上去太快玩家30秒就输了毫无成就感如果难度几乎不变玩两分钟就腻了。源码里我把难度曲线设计成随时间线性增加生成频率同时略微提高物体下落速度的函数spawn_interval max(300, 1000 - elapsed_seconds * 10) fall_speed 3 elapsed_seconds * 0.05用300毫秒作为下限防止物体生成快到来不及反应。这个公式看似简单却是这类游戏最核心的手感来源。你拿到源码后可以调整这两个参数配合自己的想法做出完全不同的节奏。6. 把20个游戏变成自己的作品可运行之后的进阶路径源码能运行只是起点真正把学习效果拉满的是在它基础上进行二次开发。下面我分享几条经过实测的高效路径也是我自己整理这批源码时实际用到的。6.1 调参数最快获得成就感的方式拿到源码第一件事不是读代码而是先改参数跑起来看效果。比如贪吃蛇游戏里的速度常量SPEED 10 # FPS越大蛇移动越快改成5跑一遍再改成20跑一遍你会立刻感受到游戏手感是怎么被一个数字影响的。同理打砖块里的球速、乒乓球AI的误差范围、扫雷的雷数密度都是可以随手改的旋钮。这种方法比逐行读代码更能帮你建立代码和运行效果之间的直接联系。建议准备一个笔记本每改一个参数就记录原值、新值、效果变化。坚持改十个参数你对游戏机制的理解会比读十遍代码更深。6.2 加功能最小的改造增量调一段时间参数后可以尝试加一个小功能这里推荐从最简单但有存在感的功能开始贪吃蛇加一条分数显示用pygame的font.text渲染到窗口顶部飞机大战加一个双发子弹道具吃到后子弹列宽度翻倍打砖块加一个挡板变宽道具持续5秒俄罗斯方块加一个下一块预览以飞机大战的双发子弹为例最小改动步骤是在子弹类里加一个count属性玩家发射时根据count创建一枚还是两枚子弹。设定道具的出现位置和碰撞检测然后在分数足够时让敌人随机掉落道具。这一整套流程走下来你会自然接触游戏开发里的实体管理事件触发Buff系统等进阶概念。6.3 换素材让游戏脱离程序员审美pygame游戏的画面观感很大程度上取决于图片和音效素材。源码里我选用的都是网上找的免费素材并规范命名放在images和sounds目录里。替换素材时注意两点一是图片尺寸最好保持原尺寸或用pygame.transform.scale调整二是带透明背景的图片要用PNG格式别用JPG。如果想获得更好听的音效可以用pygame.mixer.Sound循环播放一段低频背景音或者用pygame.mixer.music加载一个MP3作为背景音乐。源码里有的游戏自带音效文件有的则用函数自动生成简单的提示音比如def play_beep(freq440, duration0.1): # 用纯数学方式合成方波音效不依赖外部文件 sample_rate 44100 samples [] for i in range(int(duration * sample_rate)): samples.append(32767 * (1 if (i * freq // sample_rate) % 2 0 else -1)) sound pygame.sndarray.make_sound(np.array(samples, dtypenp.int16)) sound.play()6.4 把源码打包成可执行文件如果你想让游戏在没有Python环境的机器上运行可以用PyInstaller打包。我实测在Windows下打包单人游戏生成的可执行文件通常在5到15MB。命令很简单pip install pyinstaller pyinstaller -F -w -n santong game.py-F是打包成单文件-w是去掉控制台窗口。注意如果游戏用了外部图片和音效PyInstaller不会自动打包这些资源文件需要加--add-data参数或者把资源文件放到打包后的目录里。一个常见的做法是用如下方案pyinstaller -F -w --add-data images;images --add-data sounds;sounds game.py这步操作看似简单但能解决游戏写好了但只有自己能玩这个大问题。7. 常见运行错误的排查清单我帮你们逐个踩过这部分我把自己在批量测试20个游戏时遇到的所有报错整理成清单你如果运行某个游戏时遇到问题可以对照着排查。7.1 初始化相关的报错报错信息pygame.error: video system not initialized原因调用了pygame的绘图函数但之前没有调用pygame.init()或者pygame.init()失败。检查代码开头是否有pygame.init()另外个别环境需要显式设置视频模式才能绘制建议紧跟一行screen pygame.display.set_mode((800, 600))7.2 图片加载失败报错信息pygame.error: Couldnt open images/xxx.png原因当前工作目录不对程序找不到图片文件。按前面说的方法在代码开头把工作目录切到脚本所在目录问题即可解决。如果你是在IDE里用相对路径运行可以在项目根目录新建一个main.py作为入口统一负责切换目录和调用游戏模块。7.3 音效初始化失败报错信息pygame.error: ALSA: Couldnt open audio deviceLinux常见原因没有音频输出设备或者混音器初始化失败。如果只是想看游戏画面不纠结音效可以在初始化前加一行限制pygame.mixer.pre_init(44100, -16, 2, 512) pygame.init()如果仍然失败就注释掉所有mixer相关代码不影响游戏主逻辑运行。7.4 循环卡死或窗口无响应表现窗口能打开但画面一动不动点击关闭按钮也没反应。原因游戏主循环里可能存在阻塞调用最常见的是time.sleep用在关键帧之间。pygame要求主循环必须尽快结束一次迭代以便处理事件包括关闭窗口事件。把time.sleep替换成时钟控制clock pygame.time.Clock() while running: for event in pygame.event.get(): if event.type pygame.QUIT: running False # 游戏逻辑更新 pygame.display.flip() clock.tick(60) # 每帧间隔约16.7毫秒绝不阻塞事件处理7.5 文字中文乱码表现pygame窗口里显示中文标题或菜单变成方块。原因pygame默认字体不支持中文。解决办法是指定系统中文字体文件路径cn_font pygame.font.Font(C:\\Windows\\Fonts\\msyh.ttc, 24) # mac下常见的字体路径 # cn_font pygame.font.Font(/System/Library/Fonts/PingFang.ttc, 24)源码中所有带中文界面的游戏我都做了双版本适配Windows和macOS会各自加载可用的中文字体如果加载失败则回退到英文界面。8. 源码里值得反复精读的5个小而美的代码片段最后分享5个我在编写和整理这份源码时觉得特别有代表性、写得很漂亮的片段。它们未必是游戏主逻辑但每一个都能单独拿出来当作pygame工具函数用。片段1让物体平滑移动的帧率无关写法很多新手写的移动都是直接每帧加固定速度但不同机器跑60帧和144帧会导致速度差异巨大。源码里统一用基于上一帧经过时间的位移来实现帧率无关dt clock.tick(60) / 1000.0 # 秒 player.rect.x player.speed * dt * 60这样即使机器帧率波动物体移动速度也保持稳定。片段2游戏内切换场景的状态机多个游戏之间来回跳转时用一个简单的state字符串管理game_state menu # menu / playing / paused / gameover while running: if game_state menu: draw_menu() elif game_state playing: update_game() draw_game() elif game_state paused: draw_pause()这套写法能让你在同一个pygame窗口里实现菜单-开始-暂停-结束流程也是这20个游戏里好几款共通的结构。片段3碰撞后防止物体重叠的修正带速度的物体互相穿透很常见。修正方式是检测到碰撞后把物体位置回退到碰撞前的位置if player.rect.colliderect(wall.rect): player.rect.x prev_x player.rect.y prev_y片段4粒子系统的最简实现烟花效果和爆炸效果用粒子实现。粒子就是几百个有坐标、速度、生命周期的小点每帧更新位置并减少生命值class Particle: def __init__(self, pos): self.x, self.y pos self.vx random.uniform(-2, 2) self.vy random.uniform(-3, 0) self.life 60 def update(self): self.x self.vx self.y self.vy self.vy 0.1 # 重力 self.life - 1 particles [Particle((400, 300)) for _ in range(200)] particles [p for p in particles if p.life 0]烟花小游戏里就用了这段逻辑你看到屏幕上炸开的粒子背后其实就是几行坐标和速度更新。片段5让玩家按住方向键连续移动的输入方案pygame每次按键只触发一次KEYDOWN如果想实现按住方向键持续移动很多人会漏掉检测键盘当前状态。正确写法是用pygame.key.get_pressed()keys pygame.key.get_pressed() if keys[pygame.K_LEFT]: player.rect.x - 5 if keys[pygame.K_RIGHT]: player.rect.x 5这条知识我特别想强调因为至少有五分之一的新手在写按住移动时走了弯路。把这行代码记牢你在处理连续输入时能省不少事。这批源码我按运行入口、游戏说明、知识点标签、练习建议四个维度整理了配套文档每一份都标注了适用的Python和pygame版本范围、需要额外安装的依赖以及常见报错的应对方案。我自己在整理过程中也回过头重构了其中三四个游戏的代码结构最初它们能用但代码风格糟糕后来都改成了更容易读懂的写法。如果你拿到源码后第一个想看的是贪吃蛇我建议先别急着玩去把snake_body这个列表的插入、弹出逻辑读透再动手改一个穿墙模式——蛇从右边边界穿出后从左边边界进来。等这个功能加完你会发现自己对游戏逻辑就是数据变换这句话有了真正的体感。这套合集真正的价值不在游戏本身而在它给了你20个不重样的练习题目每一道题都能让你在某一个维度上比昨天的自己更强一点。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门