Why is self.kill() not removing the object from the group?

Question:

I’ve asked this question a while ago but the answers weren’t entirely helpful and I don’t believe I posted a minimum reproducible example. I’m trying to kill my bullet after some time (self.lifetime) has passed. The self.kill() command is executed, but it does not remove the bullet from the camera group, which is what I use to draw all bullets.

The relevant code:
Player.shoot():

    def shoot(self, pos):
    self.current_time = pg.time.get_ticks()
    # Allow the player to shoot (but not continuously)
    if not self.shooting and self.current_time - self.last_shot_time >= self.shoot_cooldown:
        self.last_shot_time = self.current_time
        # Setting self.shooting to True so that only one bullet is created
        self.shooting = True
        # Creating the bullet
        bullet = Bullet(self.rect.centerx, self.rect.centery, "bullet", pos, 2, a_s.camera)

    # Reset self.shooting
    self.shooting = False

Bullet.update():

    def update(self):
    # Killing the bullet after self.lifetime has passed
    if pg.time.get_ticks() - self.start_time > self.lifetime:
        self.kill()
        print("Killing")
    # Moving the bullet (accurately, self.x is float while self.rect.x can only be int)
    self.x += self.vel_x
    self.y += self.vel_y
    self.rect.x = int(self.x)
    self.rect.y = int(self.y)

Entity class: (bullet inherits from this)

class Entity(pg.sprite.Sprite):
def __init__(self, speed, group):
    pg.sprite.Sprite.__init__(self)
    self.speed = speed
    group.add(self)

I’m also adding a pastebin to allow you to reproduce this example, however you will need 3 images titled "ground.png", "player.png", and "bullet.png" in the directory to run it.

Pastebin: https://pastebin.com/Vi57HF1i

Images I use (credit to someone else, not sure where I got them from): https://imgur.com/a/Oqp4lWq

Asked By: AuraZz

||

Answers:

The problem has to do with the Multiple Inheritance. Each * Bullet has 2 base classes which are derived from pygame.sprite.Sprite So each Bullet actually consists of 2 sprites. This is not intentional and cause kill not to work. When you call kill, just the "first" pygame.sprite.Sprite object is removed from the Groups.
The problem can be reproduced with the following minimal example:

import pygame

elementGroup = pygame.sprite.Group()
entityGroup = pygame.sprite.Group()

class Element(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__() 
        elementGroup.add(self)

class Entity(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__() 
        entityGroup.add(self)

class Bullet(Element, Entity):
    def __init__(self):
        Entity.__init__(self)
        Element.__init__(self)

bullet = Bullet()

print(len(elementGroup), len(entityGroup))
bullet.kill()
print(len(elementGroup), len(entityGroup))

Output:

1 1
0 1

To solve the problem, you need to restructure your code. Each class should be derived from pygame.sprite.Sprite only once.

Answered By: Rabbid76
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.