英文:
why collide_mask is significantly slower than collide_rect in pygame?
问题
I have this piece of code here to add collision to my pygame game:
collidable_sprites = self.tiles["ground"].sprites.Sprites() + self.tiles["fg_machines"].sprites.sprites()
for sprite in collidable_sprites:
if sprite.rect.colliderect(player.rect):
And this is working smoothly at 60 fps (my fps for clock.tick
).
But, of course, that collision detection is very rough unless your game is just rectangles - which is not true in my case.
So, I switched to mask collision:
collidable_sprites = self.tiles["ground"].sprites.sprites() + self.tiles["fg_machines"].sprites.sprites()
for sprite in collidable_sprites:
if pygame.sprite.collide_mask(player, sprite):
Which works better, but drops my fps to 20.
I understand that this is far harder to calculate, but is this a good alternative to do it with a 3x frame drop?
英文:
i have this piece of code here to add collision to my pygame game:
collidable_sprites = self.tiles["ground"].sprites. Sprites() + self.tiles["fg_machines"].sprites.sprites()
for sprite in collidable_sprites:
if sprite.rect.colliderect(player.rect):
and this is working smooth at 60 fps (my fps for clock.tick)
but, of course, that collision detection is very rough unless your game is just rectangles - which is not true in my case.
so, i switched to mask collision:
collidable_sprites = self.tiles["ground"].sprites.sprites() + self.tiles["fg_machines"].sprites.sprites()
for sprite in collidable_sprites:
if pygame.sprite.collide_mask(player, sprite):
which works better, but drops my fps to 20.
i understanding that this far harder to calculate,
but is this a good alternative to do it with 3x frame drop?
答案1
得分: 3
pygame.Rect.colliderect
执行一个边界框测试,pygame.sprite.collide_rect
基于 pygame.sprite.Sprite
的 .rect
属性执行一个碰撞测试。
pygame.sprite.collide_mask
基于 pygame.sprite.Sprite
的 .rect
和 .mask
属性执行一个碰撞测试。如果精灵没有 .mask
属性,那么必须即时创建掩码。
collide_mask
比 collide_rect
慢,因为它执行一个基于重叠像素的碰撞测试,而 collide_rect
只执行一个轴对齐的边界框测试。边界框测试可以通过单个条件执行。另一方面,掩码测试必须首先找到矩形的重叠区域,然后找到重叠的像素,因此取决于两个区域或掩码的重叠区域的大小。
基本上,collide_mask
在找到矩形的交集后执行的操作与 collide_rect
相同,但之后它必须迭代掩码位以检测是否设置了重叠位。
要改善代码性能的第一件事是预先使用 pygame.mask.from_surface
创建掩码,示例如下:
class SpriteObject(pygame.sprite.Sprite):
def __init__(self, x, y, image):
super().__init__()
self.image = image
self.rect = self.image.get_rect(center=(x, y))
self.mask = pygame.mask.from_surface(self.image)
英文:
pygame.Rect.colliderect
performs a bounding box test and pygame.sprite.collide_rect
performs a collision test based on the .rect
attributes of the pygame.sprite.Sprite
.
pygame.sprite.collide_mask
performs a collision test based on the .rect
and .mask
attributes of the pygame.sprite.Sprite
. If the sprites does not have a .mask
attribute, the masks must even be created on the fly.
collide_mask
is slower than collide_rect
because it performs a collision test based on overlapping pixels, while collide_rect
only performs an axis-aligned bounding box test. A bounding box test can be performed with a single condition. The mask test, on the other hand, must first find the overlapping area of the rectangles and then the overlapping pixels, and therefore depends on the size of the overlapping area of the two areas respectively masks.
Basically collide_mask
does what collide_rect
does to find the intersection of the rectangles, but after that it has to iterate through the mask bits to detect if overlapping bits are set.
The first thing you should try to do to improve the performance of your code is to create the masks in advance with pygame.mask.from_surface
. e.g.:
class SpriteObject(pygame.sprite.Sprite):
def __init__(self, x, y, image):
super().__init__()
self.image = image
self.rect = self.image.get_rect(center = (x, y))
self.mask = pygame.mask.from_surface(self.image)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论