首页 / 资讯中心 / 文章详情

用Pygame开发你的第一个Python小游戏:从环境搭建到碰撞计分

用Pygame开发你的第一个Python小游戏:从环境搭建到碰撞计分 ★ FEATURED ARTICLE
先聊一个很多人容易忽略的前提不是所有编程项目都能带来“即时反馈”的成就感但Pygame小游戏恰恰属于那种“半小时出一个能玩的东西”的项目类型。如果你正在学Python、想找点比练习题有意思的实操或者单纯想搞明白“游戏窗口是怎么动起来的”用Pygame写第一个小游戏是个投入产出比很高的方向。这篇文章不会绕弯子直接带你从环境准备一路走到代码跑起来再把整个过程里容易踩的坑提前摆出来。1. 为什么选Pygame而不是别的库先解答一个核心问题市面上能用来写游戏的Python库不少Pygame只是之一为什么初学者最好先碰它因为Pygame的学习曲线足够平缓而且它把“游戏开发”这件事拆成了一组非常直观的积木窗口、事件、图像、声音、碰撞检测。你用Pygame写游戏基本就是在反复操作这几块积木而不是花大量时间跟复杂的引擎机制较劲。1.1 Pygame到底解决了什么问题游戏开发归根结底就三件事把画面画出来、把用户的输入接住、让画面根据逻辑不断更新。Pygame把这三件事封装成了非常直白的API。比如你要在屏幕上画一个矩形一句pygame.draw.rect()就搞定了你要监听键盘按下一句pygame.event.get()就能拿到所有按键事件。它没有Unity那种可视化编辑器也没有复杂的场景树但恰恰是这种“原始感”让你能看清游戏最本质的运行机制——一条无限循环的主循环里不断地“处理事件—更新状态—重新绘制”。1.2 适合什么基础的人上手我见过两种人特别适合从Pygame入手。一种是有Python基础、但还没做过完整项目的人Pygame能让他立刻体会到“把知识组装成一个完整作品”的感觉而且代码量不大一两个小时就能看到成果。另一种是对游戏开发感兴趣、想快速验证自己是否喜欢这行的人。Pygame的上手成本比Unity、Godot低太多——不需要安装几GB的IDE不需要学场景编辑一个编辑器、一个Python解释器就够了。需要提一嘴的是Pygame不适合追求高品质商业游戏的人它做不了复杂3D效果性能也比不上底层图形引擎但这不是它的定位。它的定位是“练手、原型验证、教学”让你用最少的代码理解游戏是怎么运作的。想清楚这一点你就明白为什么Pygame值得花时间去学。2. 环境准备与项目骨架从零到“能跑起来”磨刀不误砍柴工先把环境搭好。这个环节看着简单实际有不少人会卡在这里尤其是Python版本跟Pygame版本不匹配的问题我当年就折腾过。2.1 安装Python与Pygame的标准姿势先去Python官网下载3.9以上的版本装的时候记得勾选“Add Python to PATH”这一步漏掉的话后面命令行里敲python会直接提示找不到命令。装完Python后在命令行里验证一下python --version能正常输出版本号就说明Python本体没问题。接下来装Pygamepip install pygame如果下载速度慢可以换成国内镜像源pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple安装完毕后再验证一次python -m pygame.examples.aliens这条命令会直接弹出一个内置的“外星人”小游戏窗口如果你能看到游戏画面在跑说明环境已经完全OK了。我预计大多数人第一次看到这个自带示例窗口时都会有一种“原来就这么简单”的感觉而Pygame官网和官方文档把这件事做得非常友好每个函数都有示例代码遇到不懂的直接查官方文档是效率最高的路径。2.2 最小可运行框架游戏循环是核心把环境搞定之后先不要急着写具体功能先搭一个“最小可运行框架”。所有Pygame游戏都长这样import sys import pygame # 初始化Pygame必须放在所有pygame调用之前 pygame.init() # 创建游戏窗口参数是宽和高 screen pygame.display.set_mode((800, 600)) # 设置窗口标题 pygame.display.set_caption(我的第一个Pygame游戏) # 创建游戏时钟用来控制帧率 clock pygame.time.Clock() # 游戏主循环 while True: # 处理事件包括鼠标点击、按键、窗口关闭等 for event in pygame.event.get(): if event.type pygame.QUIT: pygame.quit() sys.exit() # 用白色填充整个窗口 screen.fill((255, 255, 255)) # 刷新画面 pygame.display.flip() # 控制游戏帧率在60FPS clock.tick(60)这段代码虽然什么都没做但它就是所有Pygame游戏的骨架。主循环的三大作用必须吃透处理事件是为了响应玩家操作更新状态是为了改变游戏逻辑重新绘制是为了让画面反映最新的状态。帧率控制非常重要clock.tick(60)的意思是“每秒最多执行60次循环”如果你不限制帧率游戏跑起来会快得离谱画面闪烁到根本没法看。我的建议是这一段代码不要复制粘贴就了事最好自己敲一遍哪怕敲错了也无所谓因为排错的过程就是你对Pygame理解加深的过程。敲完感觉没问题了再进入下一步。3. 实战做一个“接苹果”小游戏环境搭好、框架跑通现在开始写点真正能玩的东西。我选“接苹果”这个题材是因为它包含了一个游戏最核心的几大要素玩家角色的移动控制、障碍物苹果的生成与下落、碰撞检测、计分和游戏结束判定。麻雀虽小五脏俱全做完这一个你基本就能触类旁通很多2D小游戏。3.1 游戏设计思路与元素拆解先想清楚这个游戏怎么玩玩家控制一个篮子在屏幕底部左右移动苹果会从屏幕上方随机位置下落接到一个加一分漏掉一个游戏结束。游戏元素一共就三样一个篮子、一堆苹果、一个记分牌。这里的关键设计决策是苹果是不是要一次性生成一堆答案是不是。为了模拟“源源不断”的感觉我们用时间间隔来控制生成比如每秒钟生成一个苹果这样游戏难度是均匀递增的。另外苹果下落的速度可以随着分数提高而逐渐加快这样就能给玩家制造越来越强的紧张感游戏体验马上就不一样了。3.2 画角色、写移动逻辑先定义一个篮子类。用类来组织代码比到处写全局变量清晰得多这也是很多新手容易忽略的游戏代码的清晰度直接决定你后续能不能持续扩展功能。class Basket: def __init__(self, x, y, width, height, speed): self.x x self.y y self.width width self.height height self.speed speed def move(self, keys): if keys[pygame.K_LEFT] or keys[pygame.K_a]: self.x - self.speed if keys[pygame.K_RIGHT] or keys[pygame.K_d]: self.x self.speed # 防止篮子移出屏幕边界 if self.x 0: self.x 0 if self.x screen_width - self.width: self.x screen_width - self.width def draw(self, screen): pygame.draw.rect(screen, (0, 128, 255), (self.x, self.y, self.width, self.height))移动逻辑里最容易踩的坑有两个。一个是不去做边界限制导致角色移出屏幕后“失踪”。另一个是移动速度太慢或太快体感很差一般小游戏里角色速度建议在5到10像素/帧之间具体数值要自己试调试到手感对了才算好。我习惯的做法是先设一个速度跑两分钟感受一下再微调而不是一次把数值“猜准”。3.3 苹果生成与下落体验“动态”游戏世界苹果不能一开始就全生成好否则画面就空了或满了都不自然。正确做法是维护一个苹果列表每帧根据时间判断是否要生成新苹果。这里要提一个新手常见错误在无限循环里直接调用time.sleep()来控制生成间隔这样会把整个游戏卡住正确姿势是用一个计时器变量来累积帧间隔。apple_timer 0 apple_interval 30 # 每30帧生成一个苹果 while True: for event in pygame.event.get(): if event.type pygame.QUIT: pygame.quit() sys.exit() keys pygame.key.get_pressed() basket.move(keys) # 生成苹果 apple_timer 1 if apple_timer apple_interval: apple_timer 0 apple_x random.randint(basket.width, screen_width - 40) apple_y -40 # 从屏幕顶部外开始出现 apples.append(Apple(apple_x, apple_y, 30, 30, fall_speed)) # 更新苹果位置 for apple in apples[:]: apple.y apple.fall_speed if apple.y screen_height: apples.remove(apple) game_over True # 漏掉苹果游戏结束 screen.fill((255, 255, 255)) basket.draw(screen) for apple in apples: apple.draw(screen) pygame.display.flip() clock.tick(60)这里有个细节值得注意遍历apples列表删除元素时我用的是apples[:]切片拷贝来遍历而不是直接遍历原列表。因为如果在遍历过程中直接删除元素会导致跳过一个苹果或者报错这是Python里处理列表删除的经典坑游戏开发里也经常遇到。3.4 碰撞检测与计分逻辑碰撞检测听起来高大上实际在这个游戏里就是一个简洁的矩形交集判断。Pygame内置了Rect类和colliderect()方法能让我们省掉很多手写数学公式的麻烦。给篮子、苹果分别创建Rect对象然后一帧一帧地检测basket_rect pygame.Rect(basket.x, basket.y, basket.width, basket.height) for apple in apples[:]: apple_rect pygame.Rect(apple.x, apple.y, apple.width, apple.height) if basket_rect.colliderect(apple_rect): apples.remove(apple) score 1 # 每得5分加快苹果下落速度 if score % 5 0: fall_speed 1这个逻辑的重点不只是“检测到碰撞就加分”而是分数驱动的难度递进。这种设计让玩家感受到的不是“永不变的游戏世界”而是“我玩得越好挑战越大”的反馈循环游戏粘性一下子就上来了。计分界面也不要忽略。Pygame自带的默认字体就够用但要注意直接写中文会显示成方块因为默认字体不支持中文。最简单的方案是先用英文显示或者加载系统自带的中文字体。后者稍麻烦一点但值得做代码如下font_path C:/Windows/Fonts/simhei.ttf # Windows系统自带的黑体 font pygame.font.Font(font_path, 36) def draw_score(screen, score): score_text font.render(fScore: {score}, True, (0, 0, 0)) screen.blit(score_text, (10, 10))如果你用的是macOS字体路径要换成/System/Library/Fonts/PingFang.ttc之类。这里做个提醒处理中文字体是很多Pygame新手都踩过的坑我建议你写完代码后专门测一次中文显示免得所有功能都做完了才发现中文全变成方块字。4. 优化与细节打磨从“能玩”到“好玩”一个游戏代码能跑起来跟“好玩”之间还有一段距离。这段距离靠什么拉近靠细节。我见过很多人的第一个Pygame作品玩法功能都有了但体验粗糙画面干巴巴、节奏忽快忽慢、退出还容易卡死。这一节专门说怎么把这些细节补上。4.1 控制帧率与速度数值调试心法帧率控制在前面提过clock.tick(60)除了让画面稳定还直接影响游戏速度的“手感”。如果你在同一台电脑上运行60帧和30帧下的移动速度是不一样的因为你的移动逻辑里speed是按“像素/帧”来算的帧率越高单位时间内移动的像素就越多。这里有两种不同的速度设计思路。一种是把速度跟帧周期解耦用delta time每帧间隔时间来计算位移数学上精确但代码量多一点另一种是像我前面代码里那样直接按帧数控制速度然后保证tick恒定在60简单直观。我建议新手先用第二种把框架搞熟练了再接触delta time的概念一步到位学太多东西容易消化不良。调试速度数值时没有捷径只有反复玩、反复调。我的习惯是先把移动速度设为8苹果下落速度设为3然后玩三分钟记录体感“太快了/太慢了/刚好”再往反方向微调。别小看这一步一个手感好的游戏数值一定是试出来的不是算出来的。4.2 用颜色、形状和音效提升体验Pygame画图形很容易上手但很多新手把整个屏幕画得花里胡哨反而没有层次感。我的建议是遵循一个简单原则背景颜色要“后退”主角颜色要“前跳”。比如背景用浅灰色或浅蓝色篮子和苹果用高饱和度的亮色这样玩家的视线能自然落在重点上。如果每样东西都很鲜艳玩家的眼睛反而不知道该看哪里。音效是另外一个容易被忽略的环节。Pygame支持加载wav和ogg格式的音频文件接住苹果时播一个清脆的“叮”漏掉苹果时播一个低沉的音效整个游戏的质感会立刻升级。音效文件不用自己制作网上有很多免费的音效素材站可以下载注意别用mp3格式Pygame对mp3支持不太好转成wav或ogg是最稳妥的做法。pygame.mixer.init() catch_sound pygame.mixer.Sound(catch.wav) gameover_sound pygame.mixer.Sound(gameover.wav) # 在碰撞检测到苹果时调用 catch_sound.play()在我实际操作的经验里加音效的比分——写代码时要多加几行但效果立竿见影。很多试玩的朋友告诉我就是那一声“叮”让游戏突然变得“像个正经游戏了”。4.3 中文字体处理与界面美化前面提到了中文字体的问题这里展开说细一点。用系统字体虽然能解决“中文方块化”的问题但有个隐患代码换一台电脑跑字体路径可能就失效了。更靠谱的做法是把字体文件比如simhei.ttf拷贝到项目目录里然后通过pygame.font.Font(simhei.ttf, size)相对路径加载。这样你的游戏不管拷到哪台电脑上都能正常显示中文不会因为系统字体差异而出错。界面美化不只是加个文字就完事。一个好看的游戏界面至少要有几个元素标题、分数、提示语。提示语可以用稍微透明一点的颜色给玩家“次要信息”的暗示。比如分数用黑色加粗提示语用灰色玩家一眼就能分出主次。5. 常见问题与排查技巧实录整个开发过程中有几个问题出现频率极高我几乎看每个新手都会碰到。把它们集中整理出来如果你也遇到直接对号入座即可。5.1 窗口闪退问题这个问题的典型场景是双击运行代码窗口刚弹出来一瞬间就消失了。发生这种情况99%是程序出现了未捕获的异常。排查方法很简单在命令行里用python 你的文件名.py运行如果代码报错异常信息就会留在终端里不再一闪而过。还有一种可能的闪退原因是主循环里没有正确处理QUIT事件导致窗口关闭时程序走不到正常的退出流程。记住任何Pygame程序都必须在主循环里监听pygame.QUIT事件并调用pygame.quit()和sys.exit()否则关闭窗口时就会报一个奇怪的内存错误。5.2 键盘不灵或无法控制有时候键盘按键没反应最常见的两个原因一个是忘了调用pygame.key.get_pressed()来获取按键状态只用事件驱动的方式判断按下导致只会“按一下动一步”而不是“按住持续移动”。另一种可能是移动代码写了但主循环里根本没调用它或者说调用的顺序不对。排查这类问题的核心思路就一句话先在代码里加print(keys)看看按键事件有没有被触发再顺着链路往下查。5.3 游戏跑起来特别卡或特别快游戏卡顿要么是clock.tick()没有写要么是游戏里加载了太大的图片或音效。如果是帧率没限制运行速度会快到没法玩这种情况加一行clock.tick(60)就解决了。如果限制之后还是卡检查图集大尺寸图片建议预先用pygame.transform.scale()缩小再显示每帧缩放是非常消耗性能的。5.4 苹果生成与性能优化技巧当苹果数量积累到几十个时每次都要遍历所有的苹果做碰撞检测虽然不至于卡死但心里要有个数这种“遍历所有对象”的写法只适合量级小的游戏。如果苹果数量要涨到100就得考虑对象池或空间分区了。不过对第一个游戏来说把这个问题记在心里就行不用当下就解决。我见过有人一开始就折腾高级架构结果卡在一半什么都做不出来这是最可惜的。先把功能做出来再谈优化这条准则适用于所有初学者项目。6. Pygame后续还能做什么接苹果游戏做完并跑起来后你其实已经掌握了Pygame游戏开发的核心概念循环、事件、碰撞、渲染、对象管理。接下来有两条明显的进阶路线分享给你做参考。6.1 玩法扩展与关卡设计第一种是在现有游戏上做加法。可以加一个“抓满10个苹果就过关”的关卡设计难度阶梯式上升也可以加一个定时掉落的“炸弹”碰到直接扣生命值再加一个“双倍积分”道具每隔一段时间随机出现。这些玩法听起来各有不同但底层的代码实现都是你正在学的那些东西只是逻辑排列不同。用这种方式扩展你的代码复用能力会飞速提升。6.2 尝试新的游戏品类第二种是尝试一种不同的游戏品类。比如做一个像Flappy Bird那样的“点击跳跃”游戏或者一个像贪吃蛇那样的“网格移动”游戏。不同品类的游戏会让你接触新的设计模式Flappy Bird会用到重力模拟和状态机贪吃蛇会用到方向控制和蛇身跟随逻辑。每一种新游戏都会逼你学会一项新技能。倒过来Pygame官方文档里有大量现成的示例项目把示例代码读懂、改造、加入自己的想法也是一个性价比很高的学习方法。我个人在写了一系列Pygame小游戏后最大的体会是通过Pygame学到的不是某个具体API而是一套“如何把抽象逻辑拆解成可执行模块”的思维方式。这个思维方式放到任何一门编程语言、任何一个游戏引擎里都是通用的。如果你第一个游戏已经跑通了建议你现在就坐下来给自己挑一个新玩法准备开始第二次挑战——第二次会比第一次快得多有意思得多。
阅读完成 · 觉得有帮助?
咨询建站