Search code examples
pythonpygamepygame2

Issue with sprites in pygame


I am making a 2d game with lvls at lvl 4 a box should appear, after passing lvl 4 it should dissappear and be removed form the boxes list. Its removed from the boxes list but still appears on the screen. Please help me fix it.

I am making a 2d game with lvls at lvl 4 a box should appear, after passing lvl 4 it should dissappear and be removed form the boxes list. Its removed from the boxes list but still appears on the screen. Please help me fix it. I was expecting that at lvl 5 boxes list should hhave been empty and box sprite should have been dissapeared. List does get empty but the box doesn't dissappear.

import pygame

pygame.init()

clock = pygame.time.Clock()

win_res = [800, 600]

window = pygame.display.set_mode(win_res)
pygame.display.set_caption("Mini Golf")

bg_color = (120, 200, 255)
bg_image = pygame.image.load("data/images/background.png")
ground = pygame.image.load("data/images/ground.png").convert_alpha()
ground.set_colorkey((255, 255, 255))


class Sling_Shot(pygame.sprite.Sprite):
    def __init__(self, x, y, vel):
        super().__init__()
        self.image = pygame.image.load("data/images/sling_shot.png").convert_alpha()
        self.image.set_colorkey((255, 255, 255))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.vel = vel


class Stone(pygame.sprite.Sprite):
    def __init__(self, x, y, vel):
        super().__init__()
        self.image = pygame.image.load("data/images/stone.png")
        self.image.set_colorkey((255, 255, 255))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.vel = vel
        self.fired = False

    def update(self):
        if self.fired:
            self.rect.y -= self.vel


class Bird(pygame.sprite.Sprite):
    def __init__(self, x, y, vel, moving, direction):
        super().__init__()
        self.image = pygame.image.load("data/images/bird.png").convert_alpha()
        self.image.set_colorkey((255, 255, 255))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.vel = vel
        self.moving = moving
        self.dir = direction

    def update(self):
        if self.moving:
            self.rect.x += self.vel * self.dir
            if self.rect.x <= 100 or self.rect.x + self.rect.width >= 700:
                self.vel = -self.vel


def lvl_selector(lvl):
    birds = []

    match lvl:
        case 1:
            bird = Bird(365, 85, 2, False, 1)
            birds.append(bird)

        case 2:
            bird = Bird(365, 85, 2, True, 1)
            birds.append(bird)
            bird2 = Bird(365, 85, 2, True, 1)
            birds.append(bird2)

        case 3:
            bird = Bird(365, 85, 2, True, 1)
            bird2 = Bird(365, 205, 2, True, -1)
            birds.append(bird)
            birds.append(bird2)

        case 4:
            bird = Bird(365, 85, 2, True, 1)
            birds.append(bird)

        case 5:
            bird = Bird(365, 85, 2, True, -1)
            birds.append(bird)

    return birds


class Box(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.image.load("data/images/box.png").convert_alpha()
        self.image.set_colorkey((255, 255, 255))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y


def box_selector(lvl):
    boxes = []

    match lvl:
        case 4:
            box = Box(590, 119)
            boxes.append(box)

        case _:
            boxes = []

    return boxes


def game_loop():
    sling_shot = Sling_Shot(375, 500, 5)
    stone = Stone(387.5, 485, 5)

    lvl = 3

    boxes = []

    all_sprites = pygame.sprite.Group()
    all_sprites.add(sling_shot, stone)
    birds = lvl_selector(lvl)
    for bird in birds:
        all_sprites.add(bird)

    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.MOUSEBUTTONUP:
                stone.fired = True

        x = pygame.mouse.get_pos()[0]  # Get only the x-coordinate of the mouse

        if 120 <= x <= 670:
            sling_shot.rect.x = x - 25

        if not stone.fired:
            stone.rect.x = sling_shot.rect.x + 17.5

        if pygame.sprite.collide_rect(stone, sling_shot) and stone.vel < 0:
            stone.vel = -stone.vel  # Stop the stone when it hits the slingshot
            stone.rect.y = sling_shot.rect.y - 15
            stone.fired = False

            # Reset the stone's position if needed
            if not stone.fired:
                stone.rect.x = sling_shot.rect.x + 17.5

        for bird in birds.copy():
            if pygame.sprite.collide_rect(stone, bird):
                bird.kill()
                birds.remove(bird)
                if not birds:
                    stone.rect.y = sling_shot.rect.y-12.5
                    stone.rect.x = sling_shot.rect.x
                    stone.fired = False
                    lvl += 1
                    birds = lvl_selector(lvl)
                    boxes = box_selector(lvl)

        print(len(boxes))

        for bird in birds:
            all_sprites.add(bird)

        for box in boxes:
            if pygame.sprite.collide_rect(stone, box):
                stone.vel = -stone.vel

        if lvl == 4:
            for box in boxes:
                all_sprites.add(box)
            for bird in birds:
                if bird.rect.x + bird.rect.width >= 580 and bird.rect.y == 85:
                    bird.vel = -bird.vel

        if stone.rect.y <= 0 or stone.rect.y + stone.rect.width >= win_res[1]:
            stone.rect.y = sling_shot.rect.y - 12.5
            stone.rect.x = sling_shot.rect.x
            stone.fired = False

            # Clear the old birds
            for bird in birds:
                bird.kill()
            birds.clear()

            # Add new birds for the current level
            birds.extend(lvl_selector(lvl))
            boxes = box_selector(lvl)

        window.blit(bg_image, (0, 0))
        window.blit(ground, (0, 40))

        all_sprites.draw(window)
        all_sprites.update()

        pygame.display.update()
        clock.tick(60)

    pygame.quit()


game_loop()

Solution

  • It is not enough to remove the sprite from the list, you also need remove the pygame.sprite.Sprite object from the pygame.sprite.Group. Sprites can be removed with pygame.sprite.Sprite.kill or pygame.sprite.Group.remove. e.g.:

    def box_selector(lvl, boxes, sprite_group):
        
        match lvl:
            case 4:
                box = Box(590, 119)
                sprite_group.add(box)
                boxes.append(box)
                
            case _:
                sprite_group.remove(boxes)
                boxes.clear()
    
    box_selector(lvl, boxes, all_sprites)