How do I center a surface (subsurface) around a rectangle? (scaled sprite hitbox / collision rect)

后端 未结 1 1114
别那么骄傲
别那么骄傲 2020-12-07 04:28

Currently I have working code which will cycle through a spritesheet, adding each cell/image (9 in total) as a subsurface into a list. As the game updates, I am setting the

相关标签:
1条回答
  • 2020-12-07 04:38

    If you want a scaled collision rect/hitbox, you need to give your sprites a second rect (I call it hitbox here). You have to do that because pygame blits the images/surfaces at the topleft coords of the self.rect. So the first rect self.rect serves as the blit position and the self.hitbox is used for the collision detection.

    You also need to define a custom callback function for the collision detection that you have to pass to pygame.sprite.spritecollide as the fourth argument.

    def collided(sprite, other):
        """Check if the `hitbox` rects of the two sprites collide."""
        return sprite.hitbox.colliderect(other.hitbox)
    
    collided_sprites = pg.sprite.spritecollide(player, enemies, False, collided)
    

    Here's a complete example (the self.rects are the green rectangles and the self.hitboxes are the reds):

    import pygame as pg
    from pygame.math import Vector2
    
    
    class Entity(pg.sprite.Sprite):
    
        def __init__(self, pos, *groups):
            super().__init__(*groups)
            self.image = pg.Surface((70, 50))
            self.image.fill((0, 80, 180))
            self.rect = self.image.get_rect(center=pos)
            # A inflated copy of the rect as the hitbox.
            self.hitbox = self.rect.inflate(-42, -22)
            self.vel = Vector2(0, 0)
            self.pos = Vector2(pos)
    
        def update(self):
            self.pos += self.vel
            self.rect.center = self.pos
            self.hitbox.center = self.pos  # Also update the hitbox coords.
    
    
    def collided(sprite, other):
        """Check if the hitboxes of the two sprites collide."""
        return sprite.hitbox.colliderect(other.hitbox)
    
    
    def main():
        screen = pg.display.set_mode((640, 480))
        clock = pg.time.Clock()
        all_sprites = pg.sprite.Group()
        player = Entity((300, 200), all_sprites)
        enemies = pg.sprite.Group(
            Entity((100, 250), all_sprites),
            Entity((400, 300), all_sprites),
            )
    
        done = False
    
        while not done:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    done = True
                elif event.type == pg.MOUSEMOTION:
                    player.pos = event.pos
    
            all_sprites.update()
            # Pass the custom collided callback function to spritecollide.
            collided_sprites = pg.sprite.spritecollide(
                player, enemies, False, collided)
            for sp in collided_sprites:
                print('Collision', sp)
    
            screen.fill((30, 30, 30))
    
            all_sprites.draw(screen)
            for sprite in all_sprites:
                # Draw rects and hitboxes.
                pg.draw.rect(screen, (0, 230, 0), sprite.rect, 2)
                pg.draw.rect(screen, (250, 30, 0), sprite.hitbox, 2)
    
            pg.display.flip()
            clock.tick(30)
    
    
    if __name__ == '__main__':
        pg.init()
        main()
        pg.quit()
    
    0 讨论(0)
提交回复
热议问题