所以,我试图在精灵播放器传递(而非结束)另一个精灵时得到反应。
到目前为止,我的想法是这样的:
if (sprite.x +100) > player.x > (sprite.x -100) and (sprite.y +100) > player.y > (sprite.y -100):
print("hit")
# Sprite.x and y are the position of the rect, not the whole image
这有效但有一些方法可以简化它吗?我也在想如何摆脱100像素
答案 0 :(得分:2)
如果你想使用缩放的矩形来进行碰撞检测,你可以给你的原始矩形充气(或者创建一个新的矩形)并将它作为一个单独的属性分配给你的精灵(我在这里称之为hitbox
) 。原始rect
仅用于存储位置。
创建自定义碰撞检测功能,该功能必须作为collided
参数传递给pygame.sprite.spritecollide
或groupcollide
。在这个函数中,您可以使用colliderect
rect的hitbox
方法来检查它是否与另一个精灵的矩形碰撞。
def hitbox_collision(sprite1, sprite2):
"""Check if the hitbox of the first sprite collides with the
rect of the second sprite.
`spritecollide` will pass the player object as `sprite1`
and the sprites in the enemies group as `sprite2`.
"""
return sprite1.hitbox.colliderect(sprite2.rect)
然后以这种方式致电spritecollide
:
collided_sprites = pg.sprite.spritecollide(
player, enemies, False, collided=hitbox_collision)
这是一个完整的例子(红色矩形是命中框,绿色矩形是self.rect
,用作blit位置):
import pygame as pg
class Player(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = pg.Surface((30, 50))
self.image.fill(pg.Color('dodgerblue1'))
self.rect = self.image.get_rect(center=pos)
# Give the sprite another rect for the collision detection.
# Scale it to the desired size.
self.hitbox = self.rect.inflate(100, 100)
def update(self):
# Update the position of the hitbox.
self.hitbox.center = self.rect.center
class Enemy(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = pg.Surface((30, 50))
self.image.fill(pg.Color('sienna1'))
self.rect = self.image.get_rect(center=pos)
def hitbox_collision(sprite1, sprite2):
"""Check if the hitbox of the first sprite collides with the
rect of the second sprite.
`spritecollide` will pass the player object as `sprite1`
and the sprites in the enemies group as `sprite2`.
"""
return sprite1.hitbox.colliderect(sprite2.rect)
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
enemies = pg.sprite.Group()
player = Player((100, 300), all_sprites)
enemy = Enemy((320, 240), all_sprites, enemies)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEMOTION:
player.rect.center = event.pos
all_sprites.update()
collided_sprites = pg.sprite.spritecollide(
player, enemies, False, collided=hitbox_collision)
for enemy_sprite in collided_sprites:
print(enemy_sprite)
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.draw.rect(screen, (0, 255, 0), player.rect, 1)
pg.draw.rect(screen, (255, 0, 0), player.hitbox, 1)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
如果您想要一个圆形碰撞区域,您可以将pygame.sprite.collide_circle函数作为collided
参数传递。
为您的精灵提供self.radius
属性
class Player(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.radius = 100
并在主循环中将collide_circle
传递给spritecollide
。
collided_sprites = pg.sprite.spritecollide(
player, enemies, False, collided=pg.sprite.collide_circle)
答案 1 :(得分:1)
所以,这里有几件事。从你的第二个问题开始(正如我从你的编写方式中理解的那样),你想要摆脱100个像素是正确的。拥有" 100"在您的代码中随机出现的是 Magic Number / Constant ,并且编程风格很差,原因如下:
很可能,这部分代码最好还是自己的功能,所以你可以简单地使用" hitradius"作为关键字参数,然后替换" hitradius" 100。
无论是在旁边还是替代它,您都可以将hitradius作为另一个对象(即玩家或其他精灵)的属性进行跟踪,然后以相同的方式(e.g.- sprite.x - player.hitradius > player.x [etc])
替换它。如果你确定它永远不会改变,那么把它作为一个可访问的变量在某处并使用相同的技术。
def check_aura_collision(player,sprite,hitradius = 100):
""" Checks if the player sprite is within hitradius (default 100)
pixels of another sprite.
"""
if (sprite.x + hitradius > player.x > sprite.x - hitradius )\
and (sprite.y + hitradius > player.y > sprite.y - hitradius ):
print("hit")
return True
return False
至于简化逻辑,它已经足够简单了;我可能会使用绝对值,但这并不是一个有意义的改变。然而,相反,你可能有兴趣通过使用一些基本的触发来检查圆形光环而不是你现在拥有的方形光环来使它稍微复杂一些。