URLhttps://learnscript.net/zh/pygame/sprite/collision/
    复制链接转到说明  示例

    实现精灵碰撞检测的三种方式,以及如何移除精灵

    我被代码海扁署名-非商业-禁演绎
    阅读 6:09·字数 1849·发布 

    引言

    在游戏开发过程中,碰撞检测是一个常见且关键的技术问题。无论是判断道具拾取、子弹击中目标,还是角色与环境交互,都需要可靠的碰撞检测机制。Python 的 Pygame 通过其sprite模块,为开发者提供了强大的游戏精灵(Sprite)碰撞检测功能。

    本文将讲解 Pygame 中三种主要的碰撞检测方式:精灵与精灵之间、精灵与精灵组之间,以及精灵组与精灵组之间的碰撞检测,并详细介绍移除精灵的多种方法。

    示例准备

    为了演示各种碰撞检测技术,我们构建了一个简单的游戏场景。在这个场景中,玩家可以通过点击鼠标右键,在鼠标位置创建激光(Laser)对象,并与场景中的糖果(Candy)和门(Door)进行交互。

    # 定义三个精灵类
    class Candy(pygame.sprite.Sprite):
    	pass # 具体实现省略
    
    class Laser(pygame.sprite.Sprite): pass # 具体实现省略
    class Door(pygame.sprite.Sprite): pass # 具体实现省略
    # 创建对应的精灵组 cs = pygame.sprite.Group() # Candy 精灵组 ls = pygame.sprite.Group() # Laser 精灵组

    Pygame 中的碰撞检测

    Pygame 中所有Sprite对象都拥有一个rect变量,这个矩形不仅表示精灵的位置和大小,同时也作为默认的碰撞检测区域。值得注意的是,理想情况下碰撞检测区域应小于精灵的图像,并位于图像中心,以获得更真实的碰撞效果。但在本文的示例中,我们直接使用精灵表面对象创建的矩形作为碰撞区域,这可能导致碰撞现象看起来不太“真实”。

    碰撞检测方式一:精灵与精灵之间

    sprite模块提供的collide_rect函数,可以实现两个精灵对象之间的碰撞检测。

    collide_rect(left, right)

    left,right 参数

    参与检测的两个精灵对象。

    返回值

    如果两个精灵的碰撞检测区域(rect变量)有重合部分,则返回True,否则返回False

    Group对象的sprites方法返回一个包含组中所有精灵的列表。

    当检测到碰撞时,调用精灵的kill方法会将该精灵从所有包含他的精灵组中移除。由于示例通过精灵组来更新和绘制所有激光,被移除的激光会从游戏窗口中消失,其update方法也不再被调用。

    # 遍历所有激光精灵
    for l in ls.sprites():
    	# 检测激光与门的碰撞
    	if pygame.sprite.collide_rect(l, door):
    		l.kill() # 从所有包含该精灵的组中移除精灵

    碰撞检测方式二:精灵与精灵组之间

    sprite模块提供的spritecollide函数,可用于检测精灵与精灵组中所有精灵的碰撞。

    spritecollide(sprite, group, dokill, collided=None)

    sprite 参数

    参与检测的精灵对象。

    group 参数

    参与检测的精灵组。

    dokill 参数

    布尔值,决定是否自动移除精灵组中被碰撞的精灵。

    返回值

    返回一个列表,包含了精灵组中与指定精灵发生碰撞的所有精灵。

    在这个示例中,我们将dokill设为False,然后手动处理碰撞后的移除操作。Sprite对象的remove方法可以从指定精灵组中移除精灵,Group对象的remove方法可以从精灵组中移除指定的精灵。

    for l in ls.sprites():
    	# 检测激光与糖果组的碰撞,但不自动移除
    	rcs = pygame.sprite.spritecollide(l, cs, False)
    
    if rcs: # 如果发生碰撞 l.remove(ls) # 手动从激光组中移除激光 cs.remove(rcs) # 从糖果组中移除所有碰撞的糖果

    碰撞检测方式三:精灵组与精灵组之间

    sprite模块提供的groupcollide函数,可用于检测两个精灵组之间的碰撞。

    groupcollide(groupa, groupb, dokilla, dokillb, collided=None)

    groupa,groupb 参数

    参与检测的两个精灵组。

    dokilla,dokillb 参数

    布尔值,决定是否自动移除各自组中被碰撞的精灵。

    返回值

    字典,键是第一个组中被碰撞的精灵,值是一个列表,包含了第二个组中与该精灵碰撞的所有精灵。

    这种方式比较简洁,特别适合处理大量需要相互检测的对象,如子弹与敌人群体之间的碰撞。

    # 检测激光组与糖果组的碰撞,自动移除碰撞的精灵和糖果
    pygame.sprite.groupcollide(ls, cs, True, True)

    精灵移除方法

    SpriteGroup对象提供了多种移除精灵的方式,当然,你也可以通过碰撞检测函数的相关参数自动移除精灵。

    kill方法,由Sprite对象调用,可从所有包含该精灵的组中移除精灵。

    sprite.kill()

    remove方法,由SpriteGroup对象调用,可从指定组中移除精灵,或从组中移除指定精灵。

    sprite.remove(*groups)
    group.remove(*sprites)

    groups 参数

    可变参数groups所包含的位置参数,可以是Group精灵组对象,或嵌套包含Group对象的序列对象。

    sprites 参数

    可变参数sprites所包含的位置参数,可以是Sprite精灵对象,或嵌套包含Sprite对象的序列对象。

    结论

    Pygame 的sprite模块提供了全面而灵活的碰撞检测机制,开发者可以根据具体需求选择最适合的检测方式。

    内容分类

    讲解视频

    如何在 Pygame 中实现精灵、精灵组的碰撞检测·YouTube如何在 Pygame 中实现精灵、精灵组的碰撞检测·Bilibili