0

I'm attempting to make a game with python, where a character shoots at incoming waves of enemies. I have a list of bullets, a list of the enemies' bodies, and a list of their heads. For some reason when I shoot and the bullet collides with an enemy, there is one of two outcomes. Either I get an error: "List index out of range" or all the enemies that spawn after get deleted, and eventually I get the same error. How do I fix this? Also, I'm trying to get an image to appear every time I shoot a bullet (Muzzle flash), and I'm having some trouble. can anyone help

from pygame import *
import random
import math
import os #Displays the pygame window at the top left of the screen
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d, %d" %(0,25)

init() #Starts pygame
font.init()
myfont = font.SysFont("arial", 18)
#clock = time.Clock()
LENGTH = 1000 #Creates Screen that is 1000 X 700
WIDTH = 700
SIZE = (LENGTH, WIDTH)
Screen = display.set_mode(SIZE)
lastTime = time.get_ticks()
lastTime2 = time.get_ticks()
lastTime3 = time.get_ticks()

ShotCooldown = 300
GBSpawn_Rate = 1500
MuzzleFl_Length = 100


MuzzleFlash = image.load("MuzzleFlash.png")
ForestBg = image.load('ForestBackground.jpg')
RowOfBushes = image.load('Row of Bushes.png')


#Defines colours
BLACK = (0,0,0)
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
YELLOW = (253,228,74)
PATH = (232,224,136)
GRASS = (112,200,160)
CASTLE= (212,211,209)
SKIN = (222,174,150)
BULLET = (147,105,68)
GRASS2 = (180,221,160)
ROBOT = (150,150,150)

myClock = time.Clock()
running = True
CaptainY = 500
Key = 0
BulletX = 900
BulletY = 0
RidgeY = 130
Shooting = False
Shots = []
Flashes = []
Flashes_T = []
Gigabits = []
Gigabits_Heads = []
Gigabit_Health = []
Health = 100
Collided_bullet = 0
MoveUp = False
MoveDown = False 

while running:
    for evnt in event.get(): # checks all events that happen
        if evnt.type == QUIT: # if event type is quit the program stops running
            running = False
        if evnt.type == KEYDOWN:
            Key = evnt.key

            if Key == K_UP:
                MoveUp = True

            if Key == K_DOWN:
                MoveDown = True

            if Key == K_SPACE:
                Shooting = True  

        if evnt.type == KEYUP:
            Key = evnt.key

            if Key == K_UP:
                MoveUp = False

            if Key == K_DOWN:
                MoveDown = False

            if Key == K_SPACE:
                Shooting = False
                Key != K_SPACE

    draw.rect(Screen, GRASS, (0,0, LENGTH, WIDTH))


    #Draws Trees in the backgroung
    for X in range(4):
        Screen.blit(ForestBg,(X*305,-50))

    #Draws Bushes in the front
    for X in range(4):
        Screen.blit(RowOfBushes,(X*290,625))

    #draws Paths    
    draw.rect(Screen, PATH, (0,150, 1000, 75))

    draw.rect(Screen, PATH, (0,275, 1000, 75))

    draw.rect(Screen, PATH, (0,400, 1000, 75))

    draw.rect(Screen, PATH, (0,525, 1000, 75))

    #Draws castle
    draw.rect(Screen, CASTLE, (900, 125, 100, 500))
    draw.rect(Screen, BLACK, (900, 125, 100, 500),5)

    RidgeY = 130
    for X in range(10):
        draw.rect(Screen, CASTLE, (910, RidgeY, 10, 30))
        draw.rect(Screen, BLACK, (910, RidgeY, 10, 30),2)
        RidgeY += 50

    RidgeY = 130
    for X in range(10):
        draw.rect(Screen, CASTLE, (980, RidgeY, 10, 30))
        draw.rect(Screen, BLACK, (980, RidgeY, 10, 30),2)
        RidgeY += 50  

    draw.rect(Screen, CASTLE, (900,625, 100,25))
    draw.rect(Screen, BLACK, (900,625, 100,25),5)

    #Draws captain antivirus

    #Body
    draw.rect(Screen, RED, (942, CaptainY, 15, 30))
    draw.rect(Screen, BLACK, (942, CaptainY, 15, 30),1)

    #Legs 
    draw.rect(Screen, BLACK, (942, CaptainY+30, 15, 25))
    draw.rect(Screen, BLACK, (942, CaptainY+30, 15, 25),1)

    #Arm
    draw.rect(Screen, RED, (930, CaptainY+5, 20, 5))
    draw.rect(Screen, BLACK, (930, CaptainY+5, 20, 5), 1)

    #Head
    draw.circle(Screen, SKIN, (950, CaptainY-7), 10)
    draw.circle(Screen, BLACK, (950, CaptainY-7), 10,1)

    #Gun
    draw.rect(Screen, BLACK, (920, CaptainY+3, 10, 3))
    draw.rect(Screen, BLACK, (927, CaptainY+3, 3, 5))

    #Hand
    draw.circle(Screen, SKIN, (931, CaptainY+7), 3)

    draw.rect(Screen, BLACK, (935, CaptainY+55, 22, 5))

    if len(Gigabits) < 20: 
        if time.get_ticks() - lastTime2 >= GBSpawn_Rate:
            GBit_X = 0
            GBit_Y = random.choice([148, 273, 398, 523])
            Gigabit = Rect(GBit_X, GBit_Y, 15, 40)
            Gigabit_H = Rect(GBit_X, GBit_Y -20, 15, 15)
            Gigabits_Heads.append(Gigabit_H)
            Gigabits.append(Gigabit)
            Gigabit_Health.append(1)
            lastTime2 = time.get_ticks()

    #Draws enemy bodies      
    for X in Gigabits:
        draw.rect(Screen, ROBOT, X)
        draw.rect(Screen, BLACK, X, 2)

    #Draws Enemy heads
    for X in Gigabits_Heads:
        draw.rect(Screen, ROBOT, X)
        draw.rect(Screen, BLACK, X, 2)    

    #Moves Enemy body    
    for X in range(len(Gigabits)-1,-1,-1):
        if Gigabits[X][0] < 885:
            Gigabits[X][0] += 1
        else:
            del Gigabits[X]

    #moves enemy heads        
    for X in range(len(Gigabits_Heads)-1,-1,-1):
        if Gigabits_Heads[X][0] < 885:
            Gigabits_Heads[X][0] += 1
        else:
            del Gigabits_Heads[X]
            Health -= 5


    #Draws Healthbar
    if 50 < Health >= 75:
        draw.rect(Screen, WHITE, (850,40, 100,25))
        draw.rect(Screen, GREEN, (850, 40, Health, 25))
        draw.rect(Screen, BLACK, (850, 40, 100, 25),5)

    elif  25< Health >= 50: 
        draw.rect(Screen, WHITE, (850,40, 100,25))        
        draw.rect(Screen, YELLOW, (850, 40, Health, 25))
        draw.rect(Screen, BLACK, (850, 40, 100, 25),5)

    elif 0 < Health >= 25:
        draw.rect(Screen, WHITE, (850,40, 100,25))        
        draw.rect(Screen, RED, (850, 40, Health, 25))
        draw.rect(Screen, BLACK, (850, 40, 100, 25),5)

    else:
        Health = 0

    HealthTXT = myfont.render("HEALTH: " + str(Health) , 1, (0,0,0))
    Screen.blit (HealthTXT, (857,42))

    #Moves character  
    if MoveUp == True:
        CaptainY -= 5
    if MoveDown == True:
        CaptainY += 5

    if CaptainY + 60 <= 125:
        CaptainY = 70
    elif CaptainY + 60 >= 625:
        CaptainY = 565

    #Creates Shot   
    if Shooting == True:
        if time.get_ticks() - lastTime >= ShotCooldown:
            BulletY = CaptainY+3
            Bullet = Rect(BulletX, BulletY, 25, 3)
            Shots.append(Bullet)
            Flash = MuzzleFlash, (890, CaptainY)
            Flashtime = time.get_ticks()
            Flashes_T.append(Flashtime)
            Shooting = False
            lastTime = time.get_ticks()


    #Draws Shot   
    for X in Shots:
        draw.rect(Screen, BULLET, X)

    #for X in Flashes:
        ##Spot = Flashes.index(X)
        ##if time.get_ticks - Flashes_T[Spot]  <= Flash_Length:
            ##Screen.blit(X)
            ##lastTime3 = time.get_ticks()
        ##else:
            ##del X

    #if Shooting == True:
        #if time.get_ticks() - lastTime3 >= MuzzleFl_Length:
        #Screen.blit(MuzzleFlash, (890, CaptainY-3))
            #lastTime3 = time.get_ticks()

    for X in range(len(Shots)-1, -1,-1):
            if Shots[X][0] > 0:
                Shots[X][0] -= 20
            else:
                del Shots[X]

    for X in Gigabits:
        for Y in Shots:
            if X.colliderect(Y) == True:
                Spot = Gigabits.index(X)
                Gigabit_Health[Spot] -= 1
                del Y

    for X in Gigabits_Heads:
        for Y in Shots:
            if X.colliderect(Y) == True:
                Spot = Gigabits_Heads.index(X)
                Gigabit_Health[Spot] -= 1
                del Y

    if len(Gigabits) > 0:
        for X in Gigabit_Health:
            if X == 0:
                Spot = Gigabit_Health.index(X)
                del Gigabits[Spot]
                del Gigabits_Heads[Spot]
                del [X]




    myClock.tick(60)   
    display.flip()

quit()
Youssef E.
  • 43
  • 2
  • 4
  • 1
    If two people answered this at the same time, would it be a collision detection issue detection collision? – tzaman Jan 11 '18 at 22:25
  • 1
    More seriously, this is too much code. Where specifically are you having trouble? It helps if you try to localize the issue yourself, and also post your actual error output. – tzaman Jan 11 '18 at 22:27
  • Have you tried using the Python debugger `pdb` to look at the state you're in when you get an IndexError? – hdl Jan 11 '18 at 22:28
  • Possible duplicate of [Remove items from a list while iterating](https://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating) – hdl Jan 11 '18 at 22:47
  • "Also, ..." – one question at a time please. – Jongware Jan 11 '18 at 22:56

1 Answers1

1

You are deleting elements from lists while iterating over them. This is not allowed because you are decreasing the length of the lists and at the same time try to access list elements at indices that are no longer valid. Thus the IndexError you get.

See this question Remove items from a list while iterating for a way around. You should fix your code and ask a new question with a minimal correct working example for your other issue, if it isn't fixed by this fix.

hdl
  • 1,028
  • 1
  • 9
  • 23