2

I am new in Python (3 months of experience) and I just started learning Pygame. I wanted to create a Space Game that shoot the aliens but I am getting "ValueError: list.remove(x): x not in list". I tried other solutions like creating a copy of list, using "while len(listname) <= num" but still getting the same error at the same place.

Here is the Player class:

class Player:
    def __init__(self, DISPLAYSURF):
        self.PLAYER      = pygame.image.load('SpaceRocket.png') #SpaceShip by dawnydawny from Pixabay
        self.XPLAYER     = (WINDOWWIDTH / 2) - 10
        self.YPLAYER     = WINDOWHEIGHT - 75
        self.FONT        = pygame.font.Font('freesansbold.ttf', 15)
        self.PBOX        = (self.XPLAYER, self.YPLAYER, 44, 77)
        self.DISPLAYSURF = DISPLAYSURF
        self.color       = WHITE
    
    
    def spaceMessage(self, message):
       self.message = message
       self.mesg    = self.FONT.render(self.message, True, self.color)
       self.DISPLAYSURF.blit(self.mesg, [50, WINDOWHEIGHT - 500])
    
   def showScore(self, score):
       self.score = score
       self.spaceMessage("SCORE: %s" % score)

Here is the UFO class:

class UFO:
    def __init__(self, XUFO, YUFO):
        self.XUFO = XUFO
        self.YUFO = YUFO
        self.UFO  = pygame.image.load('SpaceUFO.png') #Image by Mostafa Elturkey from Pixabay
        self.UBOX = (self.XUFO, self.YUFO, 95, 52)
    
    def makeUFO(self, DISPLAYSURF):
        self.DISPLAYSURF = DISPLAYSURF
        self.DISPLAYSURF.blit(self.UFO, [self.XUFO, self.YUFO])

Here is the main game loop:

SpaceUFO    = []
SpaceBullet = []
def runGame(Player):
    global FPSCLOCK, BACKGROUNDIMG, DISPLAYSURF, SpaceUFO

    DISPLAYSURF   = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
    BACKGROUNDIMG = pygame.image.load('SpaceBackground.jpg') # Image by Free-Photos from Pixabay 
    FPSCLOCK      = pygame.time.Clock()
    Player        = Player(DISPLAYSURF)
    SpaceKill     = 0
    SCORE         = 0
    BulletSound   = mixer.Sound('BulletSound.wav') # From https://www.freesoundeffects.com/
    pygame.display.set_caption('Space Fight by MadCoderErrr')
    mixer.music.load('SpaceSound.mp3') # Music: https://www.bensound.com
    mixer.music.play(-1)

    if SpaceKill > 0:
        SpaceKill += 1
    if SpaceKill > 10:
        SpaceKill = 0

    while True:
        DISPLAYSURF.blit(BACKGROUNDIMG, [0, 0])
    
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            
        if len(SpaceUFO) < 5:
            SpaceUFO.append(UFO(round(random.randrange(0, WINDOWWIDTH - 20.0 ** 2) * 20.0) / 20.0, WINDOWHEIGHT - 570))
            print('making new aliens')
        
        for ufo in SpaceUFO.copy():
            ufo.makeUFO(DISPLAYSURF)
            ufo.YUFO += FPS / 4
        
        for ufo in SpaceUFO:
            if ufo.YUFO >= WINDOWHEIGHT:
                SpaceUFO.pop(SpaceUFO.index(ufo))
                print('Alien is gone')
            
        for bullet in SpaceBullet.copy():
            DISPLAYSURF.blit(bullet.SpaceBulletIMG, [bullet.bulletx, bullet.bullety])
            if bullet.bullety > 0:
                bullet.bullety -= FPS
            if bullet.bullety < 0:
                SpaceBullet.pop()
                print('Bullet is now gone!')
                
        if SpaceBullet:
            for b in SpaceBullet.copy():
                for u in SpaceUFO.copy():
                    if b.bullety < ufo.UBOX[1] + ufo.UBOX[3] and b.bullety > u.UBOX[1]:
                        if b.bulletx > u.UBOX[0] and b.bulletx < u.UBOX[0] + u.UBOX[2]:
                            SpaceUFO.remove(u)
                            SpaceBullet.remove(b)
                            SCORE += 1
                            print('You killed the alien')
            
        if event.type == KEYDOWN:
            if event.key == K_LEFT and not Player.XPLAYER <= 0:
                Player.XPLAYER -= FPS
            if event.key == K_RIGHT and Player.XPLAYER < WINDOWWIDTH - (FPS * 3):
                Player.XPLAYER += FPS
            if event.key == K_SPACE and SpaceKill < 10:
                if len(SpaceBullet) < 10:
                    SpaceBullet.append(Bullet(Player.XPLAYER, Player.YPLAYER))
                SpaceKill = 1
                BulletSound.play()
            
        Player.showScore(SCORE)
        DISPLAYSURF.blit(Player.PLAYER, [Player.XPLAYER, Player.YPLAYER])
        FPSCLOCK.tick(FPS)
        pygame.display.flip()
        pygame.display.update()
    
if __name__ == '__main__':
    runGame(Player)

This is the place where I always get an error:

    if SpaceBullet:
        for b in SpaceBullet.copy():
            for u in SpaceUFO.copy():
                if b.bullety < ufo.UBOX[1] + ufo.UBOX[3] and b.bullety > u.UBOX[1]:
                    if b.bulletx > u.UBOX[0] and b.bulletx < u.UBOX[0] + u.UBOX[2]:
                        SpaceUFO.remove(u)
                        SpaceBullet.remove(b)
                        SCORE += 1
                        print('You killed the alien')

This is the full traceback:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-80ff4a993e41> in <module>
    137 
    138 if __name__ == '__main__':
--> 139     runGame(Player)

<ipython-input-1-80ff4a993e41> in runGame(Player)
    115                         if b.bulletx > u.UBOX[0] and b.bulletx < u.UBOX[0] + u.UBOX[2]:
    116                             SpaceUFO.remove(u)
--> 117                             SpaceBullet.remove(b)
    118                             SCORE += 1
    119                             print('You killed the alien')

ValueError: list.remove(x): x not in list

Guys I am really clueless now, I've been coding this for almost 40 hrs but I am still struggling. Thank you guys in advance

  • Please provide the expected [MRE](https://stackoverflow.com/help/minimal-reproducible-example). Show where the intermediate results deviate from the ones you expect. Start by printing the offending variables just before the failure; work your way back to where you don't see how the values changed from what you intended. Your posted code fails to run as given, and is not at all minimal. – Prune Sep 10 '20 at 05:12
  • you should really add some `continue` logic, after removing the bullet/ufo, since the next run of the inner loop will use a bullet which isn't part of the list. if two ufo happen to be on top of another, the second hit will surely cause this error. however, it's probably not the reason for your bug. – Jakumi Sep 10 '20 at 05:16
  • As an aside, `.remove` is almost always a code smell. – Cireo Sep 10 '20 at 05:42

1 Answers1

1

The issue is seems to be cause, when multiple ufos are hit by one bullet. In this case b is tried to be removed multiple times. break the inner loop when a bullet is destroyed:

if SpaceBullet:
    for b in SpaceBullet.copy():
        for u in SpaceUFO.copy():
            if b.bullety < ufo.UBOX[1] + ufo.UBOX[3] and b.bullety > u.UBOX[1]:
                if b.bulletx > u.UBOX[0] and b.bulletx < u.UBOX[0] + u.UBOX[2]:
                    SpaceUFO.remove(u)
                    SpaceBullet.remove(b)
                    SCORE += 1
                    print('You killed the alien')
                    
                    break

I recommend to use pygame.Rect/collidepoint() for the collision test:

if SpaceBullet:
    for u in SpaceUFO.copy():
        u_rect = pygame.Rect(*u.UBOX)
        for b in SpaceBullet.copy():
            if u_rect.collidepoint(b.bulletx, b.bullety):
                SpaceUFO.remove(u)
                SpaceBullet.remove(b)
                SCORE += 1
                print('You killed the alien')
                    
                break

Note, the code can be simplified a lot by the use of pygame.sprite.Group, pygame.sprite.Sprite and pygame.sprite.Sprite.kill.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174