pygame multiple removable item

Question:

I want to make collectable and breakable items such as chest, crate, barrel, healt, coin, key in pygame.
Then when interacting with the character; when the character touches it or breaks it, I want it removed.
I can have all the items drawn on the screen as many times as I want, but when I try to remove them, either all or none of them are removed.
This time I tried another approach and used a class, in the for loop I create a class item and add it to the list, and in the main loop I draw the items in the list to the screen. If there is any interference, I remove it from the list. the problem is that when i do this i have serious fps drops.
I could not understand how to solve it and the logic of this work. Sorry if the title or question isn’t self-explanatory and I appreciate your help.
My last code;

import pygame
from pygame.locals import *

pygame.init()
surface = pygame.display.set_mode((640,256))
clock = pygame.time.Clock()
font = pygame.font.SysFont("Arial", 32)

map="0b0b0n11111"
gameMap=[(list(row)) for row in map.split("n")]

position=(0,0)
barrelList=[]
condition=True

class Barrel:
    def __init__(self,coord):
        self.coord=coord
        self.image=pygame.transform.scale(pygame.image.load("barrel.png"),(64,80))
        self.rect=pygame.Rect((coord[0],coord[1],64,80))
        
    def draw(self,surface):
        surface.blit(self.image,self.coord)

while True:
    surface.fill((0,0,0))
    for ev in pygame.event.get():
        if ev.type == QUIT:
            pygame.quit()
        if ev.type == MOUSEBUTTONDOWN:
            position=pygame.mouse.get_pos()
            
    y=0
    for layer in gameMap:
        x=0
        for tile in layer:
            if tile=="1":#tiles ... etc.
                pygame.draw.rect(surface,"cyan",(x*128,y*128,128,128))
            if tile=="b":#chest, crate, barrel, healt, coin, key ... etc.
                if condition:
                    barrelList.append(Barrel((x*128,y*128)))
                
            x+=1
        y+=1
        
    for barrel in barrelList:
        barrel.draw(surface)
        if barrel.rect.collidepoint(position):
            barrelList.remove(barrel)
            condition=False
    
    surface.blit(font.render("fps:{}".format(int(clock.get_fps())), 1, (255, 255, 255)), (0, 0))
    pygame.display.flip()
    clock.tick(60)

barrelImage=barrel

Asked By: newfile.py

||

Answers:

  1. It is sufficient to create the list of barrels once before the application loop.
  2. Remove the barrels in the event loop in case of the MOUSEBUTTONDOWN event.
  3. See how to How to remove items from a list while iterating?. Iterate through a shallow copy of the list while removing items:
import pygame
from pygame.locals import *

pygame.init()
surface = pygame.display.set_mode((640,256))
clock = pygame.time.Clock()
font = pygame.font.SysFont("Arial", 32)

mapDef = "0b0b0n11111"
gameMap = [(list(row)) for row in mapDef.split("n")]
barrelList=[]

class Barrel:
    def __init__(self,coord):
        self.coord=coord
        self.image=pygame.transform.scale(pygame.image.load("barrel.png"),(64,80))
        self.rect=pygame.Rect((coord[0],coord[1],64,80))  
    def draw(self,surface):
        surface.blit(self.image,self.coord)

for y, layer in enumerate(gameMap):
    for x, tile in enumerate(layer):
        if tile=="b":#chest, crate, barrel, healt, coin, key ... etc.
            barrelList.append(Barrel((x*128,y*128)))

run = True
while run:
    for ev in pygame.event.get():
        if ev.type == QUIT:
            run = False
        if ev.type == MOUSEBUTTONDOWN:
            for barrel in barrelList[:]:
                if barrel.rect.collidepoint(ev.pos):
                    barrelList.remove(barrel)

    surface.fill((0,0,0))
    for y, layer in enumerate(gameMap):
        for x, tile in enumerate(layer):
            if tile=="1":#tiles ... etc.
                pygame.draw.rect(surface,"cyan",(x*128,y*128,128,128))
    for barrel in barrelList:
        barrel.draw(surface)
    surface.blit(font.render("fps:{}".format(int(clock.get_fps())), 1, (255, 255, 255)), (0, 0))
    pygame.display.flip()

    clock.tick(60)

pygame.quit()
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.