0

I've been trying to create a game with PyGame but sometimes it crashes due to this error:

ValueError: <main.projectile object at 0x0000024699C2C670> is not in list

Do you know any possible fixes?

As I've seen from other people it might be that I am modifying the bullets list while I'm iterating it but i can't find a solution even reading to this thread.

PS. I know that I can use a function to spawn the goblins and not just copy and paste but this is a quick project that I am trying to get over. This is the code:

def enemy():
       def __init__(self, x, y, width, height, end):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.end = end
        self.path = [self.x, self.end]
        self.walkCount = 0
        self.vel = 3
        self.hitbox = (self.x + 17, self.y + 2, 31, 57)
        self.health = 10
        self.visible = True

bullets = []
goblin = enemy(100, 410, 64, 64, 450)

# mainloop
while run:
 if not goblin.visible:
      goblin.hitbox = 0
      for bullet in bullets:
          if 0 < bullet.x < 500:
              bullet.x += bullet.vel
           else:
                if len(bullets) != 0:
                   bullets.pop(bullets.index(bullet))
D_00
  • 1,440
  • 2
  • 13
  • 32
Kent
  • 25
  • 5
  • 1
    Can you please provide a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example)? A lot of code can be confusing, and many users could prefer skipping this post because they would have to debug the entire code. Maybe you could only post the function that returns the error? – D_00 Jun 27 '21 at 19:49
  • 1
    Sure. I cleaned it up a little bit :P – Kent Jun 28 '21 at 07:57

1 Answers1

0

The problem here seems to be that you iterate through the bullets in a for loop, and remove a bullet halfway through. The following line

for bullet in bullets:

will, in practice, go through the bullets 1 by 1 from the first to the last one, by index. That is, if your list is bullets = [bullet1, bullet2, bullet3] it will execute for bullets[0], then for bullets[1] and lastly for bullets[2]. The problem here appears when you remove a bullet from the list. Say bullet2 (which is bullets[1] gets removed in your loop. Now index will still jump up to 2, and bullets[2] will be accessed. However, there are now only two bullets, bullets = [bullet1, bullet3], and an error occurs.

If, on the other hand, bullet1 gets removed, bullets is now bullets = [bullet2, bullet3]. The loop continues to index 1, but this skips bullet2 altogether.

This is a very common problem in many programming languages. In many languages iterating the list from the last item to the first item resolves this, but this is not straightforward to do in python.

Have a look at this StackOverflow answer to get a better idea of your options.

A solution

One way to resolve the issue, which is not the most efficient but relatively easy to understand, is to construct a new list of bullets, while evaluating the bullets. Instead of removing bullets you'll be adding all bullets that persist in the new bullet list.

newBullets = []
for bullet in bullets:
          if 0 < bullet.x < 500:
              bullet.x += bullet.vel
              # append bullet to keep it
              newBullets.append(bullet)
          # else don't do anything
# after the loop, update the bullets list
# which now contains only bullets that have an x between 0 and 500
bullets = newBullets
fravolt
  • 2,565
  • 1
  • 4
  • 19