尧图精选

pygame小游戏全集怎么跑:环境搭建到避坑调试全攻略

🕒 发布时间:2026/10/1 2:07:01 📁 来源:尧图网络
简介一套基于pygame的20款小游戏合集面向Python初学者、游戏开发爱好者及编程教学场景。合集涵盖射击达人、贪吃蛇、2048、扫雷、飞机大战、外星人入侵、塔防、坦克大战等经典玩法每个游戏均有完整可运行的Python源码。使用PyCharm等IDE配置好环境后即可直接运行适合通过拆解源码学习Python语法、pygame图形与事件处理、游戏循环设计等知识。压缩包共2000个文件以1558个py源码文件为核心辅以pyc编译文件、png图片素材、wav音效和html辅助文档等整体大小约165.68MB目录结构清晰便于按项目检索。目前已有1298人下载学习。这套资源还包含地图、关卡配置及字体文件每个小游戏独立成模块既可作为入门练手项目也能为课程设计或毕业设计提供现成参考帮助读者快速掌握从零到一开发小游戏的完整流程。1. pygame小游戏全集不只有20个案例更是一套能跑的入门教材你是不是也下过那种“20个python小游戏”的源码包解压一看20个文件夹整整齐齐心里想着这下能边玩边学了。结果双击运行一半是黑屏闪退一半是报ModuleNotFoundError最后只能默默关掉。这类 pygame 小游戏全集的价值恰恰不在于那20个游戏好不好玩而在于它把pygame的核心机制——事件循环、精灵、碰撞检测、音效播放——分散到了一个个可以独立运行的例子里。你能把这20个全部跑通pygame就入门了能动手改其中几个说明你已经有了写游戏的基本盘。这篇笔记就按我的调试习惯带你把下载下来的全集从环境到运行整个捋一遍顺便把最容易翻车的几个坑提前告诉你。2. 从零跑通pygame小游戏环境、目录与最小启动代码2.1 为什么选pygame做小游戏全集开发效率与上手曲线的取舍pygame是基于SDL的Python 2D游戏开发库脚本语言写逻辑C语言跑底层所以一个几百行的main.py就能撑起一个完整的小游戏。市面上的“python小游戏源码”绝大多数都用pygame不是因为它是唯一选择而是因为它满足两个条件第一安装简单一条pip命令就能用不会像某些引擎那样还要下载IDE和构建工具第二渲染方式足够直接——你往Surface上画图翻转给屏幕整个流程一眼到底。相比Pygame Zero、pyglet这些替代品pygame的资料量和案例量是碾压级的。你搜“python小游戏”搜“pygame源码”返回的结果里大部分都能直接跑。对入门者来说遇到问题时能搜到答案比框架本身更先进重要得多。pygame的性能做2D小游戏也完全够用60帧环境下CPU占用并不夸张不需要去折腾OpenGL。更重要的是这类合集通常不带图形化编辑器所有逻辑都明明白白写在源码里学的人能直接看到“按下按键到画面变化”的完整链路。这是Unity或Godot做不到的——它们会把逻辑埋在节点和信号槽里新手根本不知道从哪看起。当然pygame也有边界不支持3D、没有物理引擎、音频功能相对基础但小游戏全集的定位本来就是“学会游戏循环和基本交互”这些边界不是问题。所以拿到一套pygame小游戏全集本质上就是拿到了一套覆盖面很全的入门题目贪吃蛇、飞机大战、打地鼠、记忆翻牌这些经典玩法正好把游戏开发里的坐标映射、碰撞检测、状态管理、计时器全部过一遍。2.2 搭建可复现的运行环境Python版本与pygame安装的注意事项很多合集下载后跑不起来不是源码不行而是环境不对。我见过的坑包括系统里装的是Python 2、pygame还停留在1.9、或者压根没装pygame。要避免这些我建议第一步就建一个干净的虚拟环境把依赖隔离起来也让以后删掉重来不费劲。在项目根目录打开终端按顺序执行下面这些命令# 创建虚拟环境避免污染系统Python python -m venv pygame_env # 激活虚拟环境Windows pygame_env\Scripts\activate # 激活虚拟环境macOS/Linux source pygame_env/bin/activate # 安装pygame建议指定版本以保持稳定 pip install pygame2.5.2 # 验证安装 python -c import pygame; print(pygame.__version__)这里指定pygame2.5.2是为了可复现。如果你直接pip install pygame装到最新版通常也没问题但老源码里如果用了pygame.sprite的内部写法版本差异会引出一些奇怪的警告。另外如果你的Python是3.8到3.11之间的版本pygame 2.x都很稳定3.12之后部分Linux发行版的wheel有兼容问题建议还是用3.10左右的版本最省心。如果下载速度慢可以加一个镜像源参数国内环境一般这样装pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pygame装完以后我习惯先跑一个最小窗口确认pygame本身能正常工作。这个最小代码也是以后所有调试的底子请记住它import pygame pygame.init() screen pygame.display.set_mode((640, 480)) pygame.display.set_caption(test) running True while running: for event in pygame.event.get(): if event.type pygame.QUIT: running False pygame.display.flip() pygame.quit()这段代码的逻辑很简单pygame.init()初始化所有模块set_mode创建窗口事件循环里等待QUIT事件flip把后台缓冲送到屏幕。如果这个窗口能稳定打开说明pygame环境没问题剩下的事就是检查源码本身了。2.3 读懂源码包的目录结构main.py、素材与模块怎么分布拿到合集先别急着运行花两分钟看目录。常见的结构是这样pygame_games/ ├── launcher.py ├── requirements.txt ├── 01_snake/ │ ├── main.py │ ├── assets/ │ │ ├── images/ │ │ └── sounds/ │ └── data.py ├── 02_plane_war/ │ ├── main.py │ └── assets/ └── 03_memory/ └── main.py每个游戏目录里至少有一个main.py图片和音效放在assets下data.py用于集中管理颜色、速度、字体这类参数。有些合集还会把公共模块抽到根目录的common.py里供多个游戏共用。你不需要读懂所有文件但至少要知道每个游戏应该包含哪些东西——如果某个游戏目录里只有main.py那它多半是纯绘制类游戏不需要素材如果素材文件夹存在但文件缺失运行时会直接报错。运行单个游戏最直接的方式是进入目录再执行cd 01_snake python main.py但合集如果没有提供launcher.py每次都要手动进目录20个游戏会把人逼疯。我一般会自己写一个启动器自动扫描子目录里的main.py做成菜单。这也是拿到新合集后的第一个实操import os import sys import subprocess def find_games(root.): result [] for name in os.listdir(root): sub_dir os.path.join(root, name) if os.path.isdir(sub_dir) and os.path.isfile(os.path.join(sub_dir, main.py)): result.append(name) return sorted(result) if __name__ __main__: games find_games() if not games: print(没找到任何含 main.py 的子目录) sys.exit(1) for idx, game in enumerate(games, 1): print(f{idx}. {game}) choice input(请输入编号启动: ) selected games[int(choice) - 1] subprocess.run([sys.executable, os.path.join(selected, main.py)])find_games用os.listdir遍历目录同时判断子目录下是否存在main.py这样能过滤掉放说明文档的文件夹。subprocess.run会阻塞直到游戏退出所以游戏结束后能正常回到菜单。注意这里的int(choice)没有做异常处理实际使用建议包一层try/except否则输入非数字会直接报错退出。进阶一点的启动器还会在启动前检查依赖这个我们放到第4章统一处理。3. 拆解三个必玩的经典案例循环、事件、碰撞是pygame的三大支柱一个pygame游戏再花哨底层也逃不开三件事主循环让画面持续更新、事件让玩家能操作、碰撞让游戏元素发生交互。下面用三个最常见的合集必玩案例把这三个支柱分别拆开看。3.1 贪吃蛇方块移动背后的坐标网格逻辑贪吃蛇是理解坐标映射的最好例子。整个游戏建立在一张网格上每个格子大小固定蛇身就是一组网格坐标的列表。你不需要关心像素级的位置只要维护一个蛇头坐标和方向向量每次移动按方向计算新头坐标即可。这是最核心的移动逻辑# 蛇身坐标列表头部在前每个元素是 (col, row) snake [(10, 10), (9, 10), (8, 10)] direction (1, 0) # (x方向增量, y方向增量)向右 def update(): head snake[0] new_head (head[0] direction[0], head[1] direction[1]) snake.insert(0, new_head) # 新头部插到列表最前 if new_head food_position: # 吃到食物不弹出尾部蛇长度1 return True else: snake.pop() # 没吃到食物弹出尾部长度保持不变 return False这里direction是向量(1, 0)代表向右移动一格(0, -1)代表向上。insert(0, new_head)把新头放最前面pop()去掉尾部正好模拟蛇的游动。如果新头和食物坐标重合就不弹尾部蛇变长。撞墙和撞自己都是基于这个坐标列表判断的撞墙检查new_head是不是超出了网格边界撞自己检查new_head是否已经在snake里。画到屏幕上时需要把网格坐标换算成像素坐标for segment in snake: col, row segment rect pygame.Rect(col * GRID_SIZE, row * GRID_SIZE, GRID_SIZE, GRID_SIZE) pygame.draw.rect(screen, (0, 255, 0), rect)这里的GRID_SIZE是一个格子占的像素数比如20。col * GRID_SIZE就是左上角的x坐标这是整个坐标映射的核心。新手最容易犯的错误是直接拿像素坐标存放在蛇身里导致移动速度和碰撞判断都对不上。如果你想调整游戏难度真正该改的参数是移动间隔时间而不是移动步长——固定步长下调整刷新速度比在同一帧里移动多格更平滑。3.2 飞机大战精灵组、碰撞检测与分数系统飞机大战几乎是每个合集必有的项目它的价值在于引入pygame.sprite模块。子弹、敌机、玩家都继承自Sprite统一放进Group里管理批量更新、批量绘制碰撞检测一条语句就能完成。我一般会把子弹和敌机写成两个类import pygame import pygame.sprite as sprite class Bullet(sprite.Sprite): def __init__(self, x, y): super().__init__() self.image pygame.Surface((8, 8)) self.image.fill((255, 255, 0)) self.rect self.image.get_rect(center(x, y)) def update(self): self.rect.y - 10 # 子弹向上飞 if self.rect.bottom 0: self.kill() # 飞出屏幕就销毁防止列表无限膨胀 class Enemy(sprite.Sprite): def __init__(self, x, y): super().__init__() self.image pygame.Surface((30, 20)) self.image.fill((255, 0, 0)) self.rect self.image.get_rect(topleft(x, y)) def update(self): self.rect.y 2 # 敌机向下飞所有Sprite子类必须定义image和rect两个属性Group才能正确绘制和碰撞。update方法会在调用group.update()时统一执行所以每个精灵只写自己的行为主循环里一行bullets.update(); enemies.update()就够了。碰撞检测用groupcollidebullets sprite.Group() enemies sprite.Group() hits sprite.groupcollide(bullets, enemies, True, True) for bullet in hits: # hits 的 key 是第一个组里的子弹 score 10groupcollide前两个参数是要碰撞的两个组后两个True表示碰撞后把子弹和敌机都删除。这个参数是游戏手感的关键如果不想让子弹穿透敌人两个都设为True如果想保留敌方子弹而只删玩家就根据实际需求调整。返回值是一个字典键是第一个Group中的精灵所以遍历hits就能拿到所有击中的子弹。把这个和pygame.sprite.spritecollide区分开后者是单个精灵与一组精灵碰撞适合检测玩家是否撞到敌机。3.3 打地鼠/记忆翻牌计时器与状态机设计这类游戏更突出时间管理和状态切换。打地鼠的地鼠出现还是消失不能靠time.sleep()控制因为sleep会卡住整个事件循环窗口会变成“未响应”。pygame真正的做法是自定义一个事件然后用set_timer让它每隔一段时间自动触发一次。import pygame pygame.init() screen pygame.display.set_mode((600, 400)) pygame.display.set_caption(Timer Demo) MOLE_EVENT pygame.USEREVENT 1 pygame.time.set_timer(MOLE_EVENT, 800) # 每800毫秒触发一次 mole_visible False running True while running: for event in pygame.event.get(): if event.type pygame.QUIT: running False elif event.type MOLE_EVENT: mole_visible not mole_visible # 翻转地鼠可见状态 screen.fill((0, 0, 0)) if mole_visible: # 在地鼠位置绘制 pygame.draw.circle(screen, (150, 100, 50), (300, 200), 40) pygame.display.flip() pygame.quit()USEREVENT是pygame预留的用户事件起点所有自定义事件从USEREVENT 1开始递增避免和内置事件撞车。set_timer的第二个参数单位是毫秒800就是0.8秒。如果你需要一次性延时然后停止用pygame.time.set_timer(MOLE_EVENT, 0)关闭定时器再配合状态判断。游戏状态可以用一个简单的枚举或字符串变量表示PLAYING、PAUSED、GAMEOVER。把事件处理、更新和绘制都包在状态判断里这是小游戏里最高频的架构。比写一堆散落的布尔变量强得多。4. 让20个游戏都能正常跑起来统一启动方式与帧率参数调优有了第2章的启动器雏形这一章把它升级得更健壮顺便解决两个常见体验问题为什么游戏在不同电脑上速度不一样为什么窗口在高分屏上小得可怜。4.1 统一入口用launcher脚本选择游戏一个能用的launcher不能只扫描目录还要做环境和异常兜底。我会把启动器放在合集根目录内容和下面的逻辑类似import os import sys import subprocess def check_pygame(): try: import pygame return True except ImportError: return False def get_game_list(): games [] for entry in os.listdir(.): if entry.startswith(_) or not os.path.isdir(entry): continue main_path os.path.join(entry, main.py) if os.path.isfile(main_path): games.append(entry) return sorted(games, keylambda x: x.lower()) if __name__ __main__: if not check_pygame(): sys.exit(缺少 pygame请先执行 pip install pygame) games get_game_list() print(可选小游戏) for i, name in enumerate(games): print(f{i1:2}. {name}) while True: raw input(输入序号或 q 退出) if raw.lower() q: break try: idx int(raw) - 1 game games[idx] except (ValueError, IndexError): print(序号无效重新输入) continue sys.exit(subprocess.call([sys.executable, os.path.join(game, main.py)]))check_pygame在启动前捕获异常比进了游戏再报错友好得多。get_game_list跳过了以下划线开头的目录这些目录通常是你的笔记或备份文件夹不是游戏本体。subprocess.call和run的区别在于直接返回退出码sys.exit会把游戏退出码透传给终端方便后续在脚本里判断运行状态。这个启动器已经能应付绝大多数合集的结构唯一的假设是每个游戏的入口都叫main.py这个约定在pygame小游戏合集里几乎百分百成立。4.2 帧率(FPS)与游戏速度clock.tick的参数陷阱很多新手把clock.tick(60)当成“游戏每秒跑60步”这方向没错但它不是精确的固定步长。tick方法返回上一次调用到现在经历的毫秒数如果你完全忽略这个返回值那游戏速度就会受屏幕刷新率和CPU性能影响。在144Hz的显示器上主循环每秒钟跑的次数远高于60物体每帧位移固定的话整体就会快得多。正确的做法是让物体的移动速度以秒为单位乘以dtdelta time来算每帧位移import pygame pygame.init() screen pygame.display.set_mode((640, 480)) clock pygame.time.Clock() x 0 # 物体横坐标 speed 300 # 像素/秒 running True while running: dt clock.tick(60) / 1000.0 # 毫秒转秒 for event in pygame.event.get(): if event.type pygame.QUIT: running False x speed * dt # 使用 dt 计算位移 screen.fill((0, 0, 0)) pygame.draw.rect(screen, (255, 255, 255), (x, 100, 40, 40)) pygame.display.flip() pygame.quit()这段代码中speed 300的意思是每秒钟物体在x轴上移动300像素。无论循环实际跑了多少帧speed * dt一帧的位移都会自动调整最终时间上的速度恒定。如果你在配置里看到speed 5这种写法多半是“每帧5像素”这种代码在60帧下看起来正常换到120帧就会飞起。这个参数是判断源码健壮性的一个快速指标。clock.tick的另一个坑是它只应出现在主循环顶部别在分支或子函数里再调。否则每帧会调用多次内部计时就会被重置导致dt极小或为零物体几乎不动。4.3 窗口大小与缩放兼容不同分辨率屏幕合集里的游戏窗口常常写死成640x480或800x600在现在的高分屏上又小又别扭。直接改源码里的set_mode尺寸会引发连锁反应坐标、字体、图片位置全都要跟着调工作量巨大。更聪明的做法是双Surface方案日志绘制在一个固定分辨率的canvas上最后一帧缩放拉伸到窗口大小。INTERNAL_W, INTERNAL_H 480, 320 # 游戏逻辑分辨率 SCREEN_W, SCREEN_H 960, 640 # 窗口实际分辨率 pygame.init() screen pygame.display.set_mode((SCREEN_W, SCREEN_H)) canvas pygame.Surface((INTERNAL_W, INTERNAL_H)) # 主循环里所有绘制都画到 canvas canvas.fill((0, 0, 0)) # ... 绘制角色、UI ... scaled pygame.transform.scale(canvas, (SCREEN_W, SCREEN_H)) screen.blit(scaled, (0, 0)) pygame.display.flip()这样游戏内的所有坐标都基于480x320放大时transform.scale会把整个画面等比例拉伸不会出现元素错位。需要注意scale每次都会生成新Surface如果窗口尺寸不变建议缓存缩放结果只在内容变化时才重新缩放。如果想在游戏内支持动态切换窗口大小可以把SCREEN_W/SCREEN_H改成从事件里读取窗口尺寸但要注意保持宽高比一致否则画面会变形。5. pygame小游戏源码常见问题避坑从双缓冲到中文乱码的5个血泪经验这部分是我拿到任何新合集之后排查问题的固定顺序。按频率从高到低记录5条踩坑每条都是现象、原因、解决一条龙。5.1 游戏窗口一闪而过事件循环被提前退出现象双击main.py窗口刚露脸就消失控制台没有报错或者报错被Windows自动关掉。原因最常见的是源码里只写了初始化代码没有进入主循环。还有的写了while True:但分支里出现了错误的break第一帧就跳出了循环。另外一些老代码把主循环写进了函数但忘了调用函数窗口建立完直接走到pygame.quit()。解决确认主循环被正确执行且退出事件被处理running True while running: for event in pygame.event.get(): if event.type pygame.QUIT: running False # 这里写更新和绘制逻辑 pygame.display.flip() pygame.quit()这个模式是pygame的“标准骨架”。如果窗口还是闪退就在主循环前打印一行日志通过控制台输出来判断是没进循环还是循环里崩了。用文本编辑器打开源码搜索while和pygame.display.flip()这两个位置占了这类问题的九成。5.2 图像有残影/卡顿缺少display.flip()或双缓冲没开现象画面上有拖影物体移动时旧位置还残留或者整个画面闪烁严重像老式幻灯片。原因pygame的绘制默认发生在后台缓冲必须调用pygame.display.flip()把后台内容一次性交换到屏幕。如果没调用你的绘制永远在不可见的缓冲里有的游戏为了“快速刷新”另用display.update()但覆盖区域不完整就会留残影。解决每一帧先清屏绘制所有物体最后翻转缓冲。screen.fill((0, 0, 0)) # 清屏 # ... 绘制所有物体 ... pygame.display.flip() # 翻转缓冲如果清屏颜色和窗口背景不一致会造成肉眼可见的闪烁。另外pygame 2.x默认双缓冲但万一你在set_mode里加了不兼容的flag也可能导致闪屏。遇到这种情况把set_mode((width, height))保持最简写法不要画蛇添足加HWSURFACE这类旧参数。5.3 中文路径或中文注释乱码编码声明与资源路径现象源码在Windows下运行注释和print里的中文变成乱码或者加载图片时提示FileNotFoundError。原因Python 3默认UTF-8但如果源码文件是GBK编码保存的pygame读取时会因为解析问题报错。另一个高发问题是资源路径用的是相对路径但你是从其他目录启动的导致找不到images/hero.png。解决在源码文件第一行加编码声明并用文件所在目录拼接资源路径# -*- coding: utf-8 -*- import os import pygame base_dir os.path.dirname(__file__) img_path os.path.join(base_dir, images, hero.png) hero pygame.image.load(img_path)os.path.dirname(__file__)得到当前源码的绝对目录再拼子路径这样不管你在哪个目录执行python main.py资源路径都是正确的。中文目录名本身在图像加载上一般没问题但pygame.mixer音频模块在Windows上对中文路径支持较差建议把带中文的素材目录改成英文这是省钱省力的好习惯。5.4 按键无响应事件类型判断错误现象键盘怎么按都没反应但鼠标点击正常或者部分按键有反应部分没有。原因事件循环里把event.type pygame.KEYDOWN写成了event.type pygame.K_LEFT后者根本不存在。还有的是在循环里多次调用了pygame.event.get()第一次把事件消费掉了第二次拿到的是空列表。解决先判断事件类型再判断键值并在整个循环里只调一次get。for event in pygame.event.get(): if event.type pygame.KEYDOWN: if event.key pygame.K_LEFT: player.x - step elif event.key pygame.K_RIGHT: player.x step如果你需要“按住方向键持续移动”KEYDOWN单次触发是不够的因为按一次只动一步。常见做法是在KEYDOWN里设置一个布尔标记在KEYUP里取消然后在主循环的每帧更新里根据标记移动。另一种替代是pygame.key.get_pressed()它返回按键状态数组适合持续移动。但注意不要把get_pressed和KEYDOWN放在同一个功能里混用两种模型一旦冲突按键灵敏度会变得不可控。这就是为什么总有人抱怨“为什么我按一下动两下”的原因。5.5 音乐/音效播放失败文件格式与初始化顺序现象游戏画面和逻辑正常但没有任何声音或者控制台报错pygame.error: Unable to open file。原因最常见的是没有调用pygame.mixer.init()或者调用顺序不对。pygame.init()并不会自动初始化mixer的所有功能需要显式准备。另外音频文件格式不兼容部分MP3文件的编码变体在pygame里打不开换成WAV或OGG立刻就好。解决先初始化mixer再加载音频全套代码如下import pygame pygame.init() pygame.mixer.init(frequency44100, size-16, channels2) pygame.mixer.music.load(bgm.ogg) pygame.mixer.music.set_volume(0.6) pygame.mixer.music.play(-1) click_sound pygame.mixer.Sound(click.wav) click_sound.play()mixer.init参数里frequency44100是CD音质标准size-16表示16位有符号采样channels2是立体声。Music适合加载较大较长的背景音乐Sound适合几十KB的短音效两者是独立的接口。play(-1)里的-1是无限循环如果你只想播一次传0或不传即可。音频不响是最玄学的问题有时候同一份文件在一台机器上正常另一台没声可以先检查系统音量再看文件格式最后才怀疑源码——顺序反了会浪费很多时间。6. 把20个案例变成自己的作品三个进阶改造方向当你把所有游戏都跑通之后会意识到重复代码飞快膨胀每个Game都是一个main.py内部都有相似的主循环事件处理逻辑几乎一样。这时候不改造后面就没法学了。6.1 用类重构重复代码把每个游戏抽象成Scene基类写一个基类把主循环、事件分发、帧率控制都放在里面子类只重写handle_event、update、drawimport pygame class Scene: def __init__(self, screen): self.screen screen self.running True self.clock pygame.time.Clock() def handle_event(self, event): pass def update(self, dt): pass def draw(self, screen): pass def run(self): while self.running: dt self.clock.tick(60) / 1000.0 for event in pygame.event.get(): if event.type pygame.QUIT: self.running False else: self.handle_event(event) self.update(dt) self.draw(self.screen) pygame.display.flip() pygame.quit()之后每一个小游戏只需要继承Scene把逻辑填进对应方法里原本200行的main.py能瘦到80行。这个结构也方便你写一个全局的launcher根据用户选择实例化不同的Scene子类真正把20个游戏统一进一个程序里。6.2 给游戏加一个暂停与存档功能暂停是状态机改造的第一步。在update入口加一个paused判断暂停时不更新逻辑但依然绘制游戏画面paused False for event in pygame.event.get(): if event.type pygame.KEYDOWN and event.key pygame.K_p: paused not paused if not paused: # 只有未暂停时才执行更新逻辑 update(dt) draw(screen)存档用json最省事把最高分和当前关卡写进文件下次启动读取import json, os SAVE_PATH save.json def save_score(score): with open(SAVE_PATH, w) as f: json.dump({max_score: score}, f) def load_score(): if os.path.exists(SAVE_PATH): with open(SAVE_PATH) as f: return json.load(f).get(max_score, 0) return 0这比用普通文本文件好得多pygame的字体渲染能直接读取到整数不需要自己解析字符串。6.3 用pygame.mixer自制音效与背景音乐先用别的工具做音频再用pygame.mixer整合。背景音乐用mixer.music承载短音效用Sound。如果想在一个游戏里实现彩蛋音效可以动态生成import array import pygame pygame.mixer.init() # 生成一段800Hz的方波持续0.1秒 buf array.array(h, [int(32000 * 0.5 if i 2000 else -32000 * 0.5) for i in range(4000)]) tone pygame.mixer.Sound(bufferbuf) tone.play()这种方式适合做临时调音真正常用的还是加载现成的wav。我自己的教训是拿到一个高质量合集先别急着全部跑一遍而是把5.1到5.5的排查顺序抄在便利贴上。因为至少有一半的“运行失败”不是源码问题而是环境或路径问题。把这些固定的坑摸熟以后你再打开任何一套pygame小游戏全集都能稳住。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →