Search code examples
pythonclasspygamespritecollision-detection

Incorrectly removing sprite group enemies in the right order


I have 2 sprite groups, one for the enemies, and one for the players weapon. An example of how I set up the enemy sprite group... (The weapon sprite group is done the same way)

class Bat(pygame.sprite.Sprite):
    def __init__(self, bat_x, bat_y, bat_image, bat_health, bat_immune, const, dash_counter, dash, dash_time, fly_count, fly_time):
        pygame.sprite.Sprite.__init__(self)
        self.bat_health = bat_health
        self.bat_immune = bat_immune
        self.const = const
        self.dash_counter = dash_counter
        self.dash = dash
        self.dash_time = dash_time
        self.fly_count = fly_count
        self.fly_time = fly_time
        self.image = bat_image
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.topleft = (bat_x, bat_y)
        self.bat_x = bat_x
        self.bat_y = bat_y
    def update(self):
        if pygame.sprite.groupcollide(all_bats, all_sword, False, True):
            self.bat_health -= 1 
        if self.bat_health == 0:
            self.kill()
        ... #Irrelevant
all_bats = pygame.sprite.Group()

def bat_create():
    bat_x = r_x*40
    bat_y = r_y*40
    bat_health = 5
    bat_immune = False
    const = 3
    dash_counter = 0
    dash = False
    dash_time = 0
    fly_count = 0
    fly_time = 0
    new_bat = Bat(bat_x, bat_y, bat_image, bat_health, bat_immune, const, dash_counter, dash, dash_time, fly_count, fly_time)
    all_bats.add(new_bat)

When the players weapon hits a bat, regardless of which is being hit, after 5 hits the first bat to spawn is killed. I have no clue why this is happening.


Solution

  • It looks like this is the issue:

    def update(self):
        if pygame.sprite.groupcollide(all_bats, all_sword, False, True):
            self.bat_health -= 1 
    

    groupcollide returns a list of collisions. The above code is checking all_bats against all_swords, so everything Vs everything. And if ( non-empty-list ) always returns True.

    So if any bat+sword collision is made, this sprite's health is is decreased. This is probably decreasing every bat's self.bat_health each time any bat collides. Thus the first item created will reach zero first.

    You need to check if "this sprite" is part of the collision. It's a fairly simply change:

    def update(self):
        hit_list = pygame.sprite.groupcollide(all_bats, all_sword, False, True):
        if ( self in hit_list ):
            self.bat_health -= 1 
    

    But it's not efficient to do a groupcollide for every bat, during each bat's update(). Perhaps move the groupcollide call to somewhere outside the .update() function, and just perform these calculations once. Pass the collision result to the sprite-update function, or suchlike.