Search code examples
pythonclasspygamespritecollision-detection

Mask collision between two sprite groups


My player attacks by throwing their weapon at the enemies. This is currently done by using a singular sword that gets thrown, then teleports back to the player to be thrown again. I want to change this so that I have a class called sword which I can call when the player wants to throw a weapon. However, I have no idea how to do collision between to sprite groups. Heres an example of how my collision currently works (Its easier to just show the whole enemy class)

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): #There is an indent in the actual code, but stack overflow removed it in copying and pasting
        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 fly(self):
        global dash_time 
        global dash
        global const
        x = player_rect.centerx - self.rect.centerx
        y = player_rect.centery - self.rect.centery
        if x == 0:
            x = 0.1
        if y == 0:
            y = 0.1
        self.dash_counter = random.randint(0, 120)
        if self.dash_counter == 30:
            if self.dash == False:
                self.dash_time = pygame.time.get_ticks() ##def self in __init__
                self.dash = True
                self.const = 5.5
        if pygame.time.get_ticks() - self.dash_time > 1500:
            self.dash = False
            self.const = 3
        norm = (x**2 + y**2)**0.5
        self.bat_x += self.const * x / norm
        self.bat_y += self.const * y / norm

        if self.const * y / norm > 0:
            if self.fly_count == 0:
                self.image = bat_front1
                self.fly_time = pygame.time.get_ticks()
                self.fly_count = 1
            if self.fly_count == 1:
                if pygame.time.get_ticks() - self.fly_time > 600:
                    self.image = bat_front2
                    if pygame.time.get_ticks() - self.fly_time > 1200:
                        self.fly_count = 0



        if self.const * y / norm < 0:
            if self.fly_count == 0:
                self.image = bat_back1
                self.fly_time = pygame.time.get_ticks()
                self.fly_count = 1
            if self.fly_count == 1:
                if pygame.time.get_ticks() - self.fly_time > 600:
                    self.image = bat_back2
                    if pygame.time.get_ticks() - self.fly_time > 1200:
                        self.fly_count = 0            


    def update(self): ##RELEVANT##
        global player_immune
        global player_health
        global immune_time
        global player_hitsound
        global enemy_hitsound
        global dmg_multiplier
        self.rect.topleft = (self.bat_x, self.bat_y)       
        bat_immune = False
        bat_health = 5
        offsetP2B = (int(x - self.bat_x), int(y - self.bat_y)) #Player to Bat
        resultP2B = self.mask.overlap(player_mask, offsetP2B)
        if resultP2B:
            if player_immune == False:
                if invincibility_potion_activ == False:
                    player_health -= 1 
                    player_hitsound.play()
                    immune_time = pygame.time.get_ticks()
                    player_immune = True

        offsetS2B = (int(fx - self.bat_x), int(fy - self.bat_y)) #Sword to Bat 
        resultS2B = self.mask.overlap(sword_mask, offsetS2B)
        if resultS2B:
            if self.bat_immune == False:
                if fire == True:
                    self.bat_health -= 1 * dmg_multiplier
                    enemy_hitsound.play()
                    self.bat_time = pygame.time.get_ticks()
                    self.bat_immune = True    
        if self.bat_health <= 0:
            self.kill()

        if self.bat_immune == True:
            if pygame.time.get_ticks() - self.bat_time > 100:
                self.bat_immune = False        
        self.fly()  

    all_bats = pygame.sprite.Group()

This works perfectly, but I want my weapon to be like the enemies, a sprite group so I can have multiple on the screen at one time, but then how would I do the collision?? I honestly have no clue how to work around this problem!


Solution

  • I believe pygame.sprite.groupcollide() is what you are looking for? "Find all sprites that collide between two groups."

    You could also use pygame.sprite.spritecollideany() if you wanted to go through them one sword at time.