这是使用Pygame编写游戏系列教程的第七篇文章。前五篇如下:
少儿编程之使用PyGame编写游戏(1)PyGame模板
少儿编程之使用PyGame编写游戏(2):与小精灵(sprites)共舞
少儿编程之使用PyGame编写游戏(3):Sprite拾遗补缺
少儿编程之使用PyGame编写游戏(4):太空大撞击 游戏,第一步
少儿编程之使用PyGame编写游戏(5):太空大撞击 游戏,第二步
少儿编程之使用PyGame编写游戏(6):太空大撞击 游戏,加入敌人和碰撞检测
我们的碰撞发生了什么?
在上一篇教程中,我们使用图片,将我们的精灵从普通的矩形更改为更好看的 PNG 图像。 然而,这带来了一个问题:有时游戏会计算玩家与敌方精灵之间的碰撞,而敌方精灵看起来根本没有命中。 为了理解发生了什么,让我们看一个示意图:
Pygame 中默认的碰撞类型是使用 collide_rect() 函数,该函数使用两个精灵的 rect 属性来计算它们是否重叠。 这被称为 AABB 碰撞,它非常快速且可靠。 但是,如果精灵图像不是矩形,那么您会得到如图所示的情况: 矩形确实是重叠,所以 collide_rect() 为 True,但玩家会感到沮丧,因为他们觉得他们应该成功地躲过了敌人。
如果我们发现自己处于这种情况,可以尝试以下方法:
通过使用 collide_rect_ratio() 函数,您可以使用较小的矩形,从而减少可能算作重叠的“空白”空间量。 根据精灵的形状,这可以很好地工作。 请注意上图中船翼的尖端是如何在矩形之外的。 这意味着在某些情况下,流星似乎会穿过机翼而不会被视为命中。 这在实际游戏中是没问题的,因为以游戏中事物移动的速度,玩家基本不会注意到这一点,但会觉得他们“逃脱了”非常接近的碰撞。 他们不会感到沮丧,而是会觉得自己做得很好。
另一种选择是使用圆形边界框。 在游戏敌方精灵是陨石的情况下,还是不错的。 它也并不完全匹配玩家的宇宙飞船,但正如前面所述,飞船的机翼在碰撞之外也并非是一件坏事。
设置精灵的半径
基于上述选项,我们将为流星与玩家碰撞设置圆圈。 Pygame 使这很容易做到——我们只需要在每个精灵上设置一个新属性:self.radius。
让我们从玩家角色开始。 碰撞圈应该有多大? 可能需要进行一些尝试才能获得正确的值。 在播放器精灵的 __init()__
中,可以如下设置:
self.rect = self.image.get_rect()
self.radius = 25
pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
我们在玩家图片之上画了一个红色圆圈,以便我们可以直观看到效果。 让我们对敌方精灵也采用同样的方法:
self.rect = self.image.get_rect()
self.radius = int(self.rect.width / 2)
pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
在这个例子中,我们做了一些前瞻性的设置:后续我们可能会决定使用不同大小的敌方精灵图像,通过将半径设置为图像宽度的 1⁄2,我们可以在后续无需调整代码而让所有的角色均实现一样的效果。
这是我们最终的结果:
你可以看到我们对于玩家精灵的半径可能太大了——实际上它在 y 轴上比船的大小更大。 为了更接近上面的示例,让我们在播放器上设置 self.radius = 20。
对于敌方精灵,我们希望图片有一点点突出在圆圈⭕️之外,所以让我们将圆缩放到图片大小的85% :
self.radius = int(self.rect.width * .85 / 2)
更改碰撞类型
要让游戏开始使用这些圆圈进行碰撞测试,我们只需将 spritecollide 命令更改为使用 circle 函数而不是 AABB 函数:
# check to see if a mob hit the player
hits = pygame.sprite.spritecollide(player, mobs, False, pygame.sprite.collide_circle)
if hits:
running = False
通过不停地尝试,当我们对碰撞方式已经感到满意时,就可以删除红色圆圈。 建议只是将注释掉而不是删除它们,这样将来想再次使用它们时,可以只需要将注释去掉即可。
小结
选择正确的碰撞风格可以对你的游戏感觉产生很大的影响。 我们现在有了更好的敌方与玩家碰撞的方式,但请注意我们没有更改子弹与流星碰撞的样式。 圆形对于子弹的形状来说是一个不够好的选择,所以最好将它们保留为矩形。
完整的代码请查看好学好教少儿编程平台Python编辑器,直接点击运行查看Pygame游戏运行效果。
Pygame教程:太空大碰撞,改进碰撞检测算法 配套代码
在下一部分中,我们将通过学习如何将动画添加到我们的 sprite 中来使角色变得生动起来。