Nate.Olson
Nate.Olson

Reputation: 153

Iterating Through Lists (index out of range)

Quick summary of what I am creating: It is a game in which an alien spaceship bounces around the screen (like the dell logo/loading screen) with a certain boundary so that it stays near the top of the screen. Near the bottom of the screen there is a player ship that has to click to shoot the enemy space invaders style, while moving side to side (but at the moment I'm still working on keyboard/mouse working simultaneously because events only do the top of the queue). There are also cows being beamed up from beneath you by the mothership. If you catch the cow you get points. If you fail to dodge one, you lose points and a life. If you catch one with a "net" you get points.

The issue I am having is this error (cowRect = (cow_x[i], cow_y[i], 127, 76) IndexError: list index out of range), which I think would be caused by theprogram attempting to iterate through the lists while they are still empty, although it seems like items are in the list when it is "scanning" through it.

Some snippets of my code (It's like 170 lines so I won't post it all):

Beginning-

cowList = []
statusList = []
cow_x = []
cow_y = []

Inside main loop-

if hits >= hitsNeeded and time.time() >= currentTime + 1:
        cowList.append(cownumber)
        cownumber += 1
        statusList.append(3)
        cow_x.append(random.randint(0, 573))
        cow_y.append(700)

Also inside main loop-

for i in statusList:
        cowRect = (cow_x[i], cow_y[i], 127, 76)
        if cow_y[i] + 111 < 0:
            statusList[i] = 0  #offscreen
        if cowRect.colliderect(missileRect):
            statusList[i] = 1  #exploded
            points -= 15
        netRect = (net_x, net_y, 127, 127)
        if cowRect.colliderect(netRect):
            points += 90
            screen.blit(milkplus, (cow_x[i], cow_y[i]))
            powerup = pygame.mixer.Sound("C:/Python35/powerup.mp3")
            powerup.play()
            shotNet = 0
            statusList[i] = 2  #caught
        if cowRect.colliderect(playerRect):
            points -= 10
            lives -= 1
            statusList[i] = 4  #player collision

    for i in statusList:
        if statusList[i] == 3:  #alive
            screen.blit(cow, (cow_x[i], cow_y[i]))
            cow_y[i] -= cowSpeed

Yes, I do realize that I don't really need to have 4 states of cow, it just helps to keep my head organized (that goes for some other things in here too).

I apologize if I have made some mistake, I haven't been on here in a very long time.

Upvotes: 0

Views: 78

Answers (1)

chthonicdaemon
chthonicdaemon

Reputation: 19770

The problem you are seeing is due to the way that for loops work in Python. They iterate through the contents of the list, not the list indexes. As mentioned in the comments, you could fix the error by simply doing for i in range(len(statusList)), but I want to suggest that you rather use a slightly different strategy to encode the information about the cows, by having a list of cows rather than four lists about the cows.

class Cow:
    def __init__(x, y):
        self.status = 'alive'
        self.x = x
        self.y = y

Beginning-

cows = []

Inside main loop-

if hits >= hitsNeeded and time.time() >= currentTime + 1:
    cows.append(Cow(random.randint(0, 573), 700))

Also inside main loop-

for cow in cows:
    cowRect = (cow.x, cow.y, 127, 76)
    if cow.y + 111 < 0:
        cow.status = 'offscreen'
    if cowRect.colliderect(missileRect):
        cow.status = 'exploded'
        points -= 15
    netRect = (net_x, net_y, 127, 127)
    if cowRect.colliderect(netRect):
        points += 90
        screen.blit(milkplus, (cow.x, cow.y))
        powerup = pygame.mixer.Sound("C:/Python35/powerup.mp3")
        powerup.play()
        shotNet = 0
        cow.status = 'caught'  #caught
    if cowRect.colliderect(playerRect):
        points -= 10
        lives -= 1
        cow.status = 'collision'

for cow in cows:
    if cow.status == 'alive':
        screen.blit(cow_pic, (cow.x, cow.y))
        cow.y -= cowSpeed

This will make things easier in the future. If you are uncomfortable with classes, you can get similar behaviour with collections.namedtuple.

Upvotes: 2

Related Questions