
在32课里我们学了将自己喜欢的飞船放入游戏窗口中,飞船可以在屏幕上自由移动,头顶上还挂着一条红色的生命条。越来越有意思了!
Tyree玩了一会儿,觉得不过瘾:“只有飞船在空荡荡的黑色背景上飞来飞去,太无聊了。能不能发射子弹?有没有敌人?”
答案是当然可以。今天我们就给游戏加上子弹和陨石。
当子弹碰到陨石时,陨石消失,分数增加。这就是游戏里最核心的‘碰撞检测’。
他兴奋地搓了搓手:“那我得赶紧给飞船装个激光炮!”
今天就来学习碰撞检测代码怎么写。
你将会学到怎么用子弹列表管理多颗子弹,怎么用`pygame.Rect` 的 `colliderect` 方法判断两个矩形是否相撞,以及如何让陨石随机出现并向下移动。
掌握之后,你的游戏就会有了完整的“射击”要素。
01. 设计思路:子弹和陨石都是矩形
在pygame中,判断两个物体是否碰撞最常用的方法是:
用`pygame.Rect` 对象(矩形)来表示每个物体的位置和大小,然后调用 `rect1.colliderect(rect2)` 检查它们是否重叠。
飞船:我们已经有了`ship_rect`。
子弹:可以画一个小矩形,从飞船顶部发射,向上移动。
陨石:画一个棕色圆形或矩形,从屏幕顶部随机位置出现,向下移动。
当子弹的矩形与陨石的矩形重叠时,就表示“击中”。陨石消失,分数增加,子弹也消失。
02. 先让飞船发射子弹
我们用列表`bullets` 来存储所有子弹的矩形。按空格键时,在飞船顶部中央添加一颗新子弹。
代码如下:

这里pygame.Rect(x, y, width, height) 创建一个矩形,x,y 是左上角坐标。
ship_rect.centerx 是飞船矩形的中心 x 坐标,减去子弹宽度的一半(2)让子弹居中。
ship_rect.top - 5 让子弹出现在飞船正上方,避免重叠。
子弹宽4,高10,是一个细长的黄色条。
把每个新子弹添加到bullets 列表,之后在每一帧绘制所有子弹。
然后在主循环中,更新所有子弹的位置(向上移动),并移除超出屏幕的子弹。
for bullet in bullets[:]: # 用副本遍历,以便安全删除
bullet.y -= 10
if bullet.bottom < 0: # 超出屏幕顶部
bullets.remove(bullet)
bullets[:] 是列表的副本,用于遍历。因为我们在循环中会修改原列表(删除子弹),直接遍历原列表会导致跳过元素或报错。
bullet.y -= 10 每次让子弹向上移动10像素。
bullet.bottom < 0 检查子弹的底部是否已经超出窗口顶部(y坐标 < 0),如果是则移除。
绘制子弹:用`pygame.draw.rect` 画黄色小矩形。
for bullet in bullets:
pygame.draw.rect(screen, (255, 255, 0), bullet)
03. 添加陨石
陨石也用列表存储。每隔一段时间(比如30 帧)随机生成一颗陨石。
陨石的矩形可以是一定的宽度和高度,出现在屏幕顶部随机x 坐标。
代码如下:

meteor_timer 是一个计数器,每帧加1。当它超过30时,重置为0并生成一颗新陨石。这样陨石不会无限生成,而是有节奏地出现。
random.randint(0, 800-40) 确保陨石不会超出窗口右边界(陨石宽40)。
y = -40 让陨石从屏幕上方外部进入,看起来像是从顶部掉下来。
陨石矩形宽40高40,是一个正方形。
同样用[:] 遍历副本。
meteor.y += 5 向下移动。
meteor.top > 600 陨石顶部超出窗口底部(窗口高600),移除。
meteor.center 获取矩形的中心点坐标。
20 是圆的半径(因为矩形宽40,半径20刚好填满)。
04. 碰撞检测:子弹 vs 陨石
双重循环:遍历每颗子弹和每个陨石,判断是否碰撞。注意要在遍历时安全删除。

这里用`colliderect` 方法直接判断两个矩形是否重叠。击中后增加分数,并移除子弹和陨石。
外层循环子弹,内层循环陨石,检查每一对组合。
bullet.colliderect(meteor) 返回 True 如果两个矩形重叠(即碰撞)。
碰撞后:移除子弹和陨石,分数加10。
break 跳出内循环,因为当前子弹已经击中陨石,没必要再跟其他陨石比较。
注意:遍历时都用了[:] 副本,但这里删除的是原列表中的元素,而副本遍历不受影响。
05. 整合全部代码
下面把以上所有内容整合成一个完整的游戏。
篇幅太长,下面只贴出新增和修改的关键部分,完整代码会在最后给出。




同样遍历陨石副本。
如果飞船矩形与陨石矩形重叠,生命值减10,移除陨石。
生命值≤ 0 时游戏结束。
06. 完整代码(可直接运行)
下面是完整代码,可直接运行,因篇副过长,详情代码在评论区




运行后,就可以玩游戏啦,下图就是我们玩的截图



赶快动手起来,做一个自己可以玩的游戏吧!
07. 今天学到了什么
`colliderect`:判断两个矩形是否重叠,是pygame 中最常用的碰撞检测方法。
列表管理多个对象:子弹和陨石都用列表存储,用`for` 循环更新和绘制。
安全删除:遍历列表时用`[:]` 创建副本,避免“修改列表的同时遍历”出错。
定时生成:用一个计数器,每帧加1,达到阈值时生成新陨石。
游戏循环的结构:事件处理→ 移动更新 → 碰撞检测 → 绘制 → 刷新。
Tyree看到飞船能发射黄色子弹、陨石被击中后消失,开心地喊:“我终于做出真正的射击游戏了!”
下一节课我们将为游戏:添加音效和背景音乐——让游戏更带感。我们会到学习怎么用`pygame.mixer` 播放射击音效和爆炸声。
————热门推荐————
少儿自编程第31课:pygame入门——创建游戏窗口和游戏主循环,做一个自己的游戏
自学编程第8课:turtle画对称图形(彩色螺旋、彩色对称花、等边三角形、五角星)
自学编程第7课:turtle画图入门(画一个正方形,五角形,螺旋形,三角形)
自学编程第2课:用input让电脑问你名字(做一个打招呼程序)
自学编程第一步:安装Python和Thonny(零基础图文教程)
(本系列教程每天更新,欢迎关注收藏)