Python中pygame模块pygame.sprite.groupcollision碰撞检测的详解与测试

在游戏开发中,非常重要的编程工作就是进行碰撞检测。在python的pygame模块中的sprite精灵类提供了多种方便快捷的碰撞检测方法。比如矩形碰撞检测、圆形碰撞检测、遮罩碰撞检测,这些方法基本都是单个对单个的物体进行检测,如果涉及到敌我双方都有很多对象时,比如飞机大战中的我方子弹与地方飞机的碰撞检测,用上述方法可能就得进行循环嵌套,这样略显麻烦。
针对分组对象的碰撞检测,pygame中还有一种简单的碰撞检测方法:pygame.sprite.groupcollision(),网上关于介绍它的详细使用方法的文章不多,我经过反复研究和测试,终于弄清楚了它的使用方法、使用场景以及使用效果,希望对你有参考价值。

一、 功能说明

官方文档如下:
Find all sprites that collide between two groups.
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
This will find collisions between all the Sprites in two groups. Collision is determined by comparing the Sprite.rect attribute of each Sprite or by using the collided function if it is not None.
Every Sprite inside group1 is added to the return dictionary. The value for each item is the list of Sprites in group2 that intersect.
If either dokill argument is True, the colliding Sprites will be removed from their respective Group.
The collided argument is a callback function used to calculate if two sprites are colliding. It should take two sprites as values and return a bool value indicating if they are colliding. If collided is not passed, then all sprites must have a “rect” value, which is a rectangle of the sprite area, which will be used to calculate the collision.
简要解释如下:
找出两个精灵组中发生碰撞的所有精灵,主要通过比较每个精灵的Sprite.rect属性来实现。参数含义如下:
Group1:第一个精灵组
Group2:第二个精灵组
Dokill1:设置为True或者False,当设置为True时,当发生碰撞时group1中的相应精灵对象将被删除;当设置为False时,不论是否发生碰撞,group1保持不变。
Dokill2:设置为True或者False,当设置为True时,当发生碰撞时group2中的相应精灵对象将被删除,不论是否发生碰撞,group1保持不变。
Collided是个回调函数,使用默认即可。
返回值是个字典,未发生碰撞时,字典为空。发生碰撞时,字典的keys是group1中发生碰撞的对象(一直以为字典的keys值是个字符串之类的东西,没想到还可以是对象),values是一个列表,其元素是group2中与每一个group1发生碰撞的所有对象。

二、实例测试

Groupcollide返回值的形态和使用的理解是个难点,举例说明:比如group1有三架飞机对象p1、p2、p3,group2有八个子弹对象b1、b2、b3、b4、b5、b6、b7、b8,假如p1与b1、b4、b7发生碰撞,p2与b2、b5、b8发生碰撞,groupcollide(group1, group2, 1, 1)返回值是如下的字典:{p1:[b1, b4, b7], p2:[b2, b5, b8]}。
做了个小的测试程序,对上面各种情形进行测试:界面中间布置了四架飞机,上方布置了20颗子弹,子弹从上方匀速往下运行,进行碰撞检测,下图为运行之初的状态显示。
飞机大战碰撞检测

子弹往下运动,调用下面的函数进行碰撞检测:

co_dict = pygame.sprite.groupcollide(plane_list, bullet_list, 1, 1)

发生碰撞之后的状态显示如下,可以看出,四架飞机和14颗发生碰撞的子弹都消失了,因为dokill1和dokill2两个参数都被设置为1,也就是说发生碰撞的飞机和子弹都从plane_list 和bullet_list中删除了,此时plane_list是个空的sprite组了,bullet_list的长度也变成6了(刚开始的长度为20)。
飞机大战碰撞检测

此时打印返回值co_dict结果如下:
{<PlayerPlane Sprite(in 1 groups)>: [<Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>], <PlayerPlane Sprite(in 1 groups)>: [<Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>], <PlayerPlane Sprite(in 1 groups)>: [<Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>], <PlayerPlane Sprite(in 1 groups)>: [<Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>, <Bullet Sprite(in 0 groups)>]}
从上可以看出,返回值是个字典,其有4个键值对,每个键为发生碰撞的飞机精灵对象,每个值为与某一飞机发生碰撞的子弹精灵对象列表。
从上面的测试结果可以看出,groupcollide不仅可以进行碰撞检测并返回碰撞结果,还可以对参与碰撞检测的对象进行修改,如果将上述函数的dokill1的参数改为0,则plane_list中的飞机保持不变,bullet_list中发生碰撞的子弹被移除了,运行效果如下:
飞机大战碰撞检测

三、实际应用

对于需要分组碰撞检测的情形,比如坦克大战,飞机大战,用groupcollide进行检测就便利多了,只需一行代码就可以代替繁杂的多层循环嵌套了,同时还可以参与碰撞检测的对象进行修改,对于碰撞后消失的对象,不需要另外再进行if判断和手动删除了,确实是一举多得。
对于返回字典的使用,经常会遇到碰撞后需要进行爆炸显示,此时就可以对返回字典进行遍历(既可以对key遍历,也可以对value遍历),对每个对象添加一个爆炸效果即可。

  • 8
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
根据提供的引用内容,没有直接涉及到pygame.sprite.sprite()的介绍或演示。但是可以根据提供的引用内容介绍pygame.sprite模块的一些基本概念和用法。 pygame.sprite模块提供了一个用于处理精灵(sprite)的类和函数。精灵是游戏的基本元素,通常是游戏的角色、道具、场景等。pygame.sprite模块提供了一些用于处理精灵的类和函数,包括SpriteGroup、LayeredUpdates等。 Sprite类是所有精灵类的基类,它提供了一些基本的属性和方法,例如rect、image、update等。Group类是精灵组的基类,它提供了一些用于管理精灵的方法,例如add、remove、update等。LayeredUpdates类是对Group类的扩展,它提供了一些用于处理精灵层级关系的方法,例如move_to_front、move_to_back等。 在使用pygame.sprite模块时,通常需要先创建一个精灵类,然后创建一个精灵组,并将精灵添加到精灵组。然后在游戏循环,调用精灵组的update方法更新精灵状态,并调用精灵组的draw方法绘制精灵。 下面是一个简单的示例代码,演示了如何使用pygame.sprite模块创建精灵和精灵组,并将精灵添加到精灵组: ```python import pygame # 定义精灵类 class MySprite(pygame.sprite.Sprite): def __init__(self): super().__init__() self.image = pygame.Surface((50, 50)) self.image.fill((255, 0, 0)) self.rect = self.image.get_rect() def update(self): self.rect.x += 1 # 初始化pygame pygame.init() # 创建窗口 screen = pygame.display.set_mode((640, 480)) # 创建精灵组 sprites = pygame.sprite.Group() # 创建精灵并添加到精灵组 sprite = MySprite() sprites.add(sprite) # 游戏循环 running = True while running: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # 更新精灵状态 sprites.update() # 绘制精灵 screen.fill((255, 255, 255)) sprites.draw(screen) # 刷新屏幕 pygame.display.flip() # 退出pygame pygame.quit() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值