Search code examples
pythonfor-looppygamecollision-detection

"Object is not iterable", after being previously iterable


Im creating a space invaders game. (Very unfinished)

Upon adding a collision check, the check is stopping one of my previously working "for" loops from iterating. I'm assuming it has something to do with me deleting from the iterable values, but I just cant figure out how to fix it!

Any help would be very much appreciated!

import pygame,time,sys,random

BLACK=(0,0,0)
WHITE=(255,255,255)
RED=(255,0,0)
BLUE=(0,0,255)
GREEN=(0,255,0)

Done=False
clock=pygame.time.Clock()

class Invader(pygame.sprite.Sprite):
    def __init__(self, colour):
        super(Invader , self).__init__()
        self.image=pygame.Surface([20,20])
        self.image.fill(colour)
        self.rect=self.image.get_rect()


class Player(pygame.sprite.Sprite):
    def __init__(self, colour):
        super(Player, self).__init__()
        self.image=pygame.Surface([20,20])
        self.image.fill(colour)
        self.rect=self.image.get_rect()

class Player_bullet(pygame.sprite.Sprite):
    def __init__(self, colour):
        super(Player_bullet, self).__init__()
        self.image=pygame.Surface([5,15])
        self.image.fill(colour)
        self.rect=self.image.get_rect()

    def update(self):
        self.rect.y-=10
        pygame.sprite.groupcollide(obstacles_sprite,player_bullet_sprite,False,True)

class Invader_bullet(pygame.sprite.Sprite):
    def __init__(self, colour):
        super(Invader_bullet, self).__init__()
        self.image=pygame.Surface([5,15])
        self.image.fill(colour)
        self.rect=self.image.get_rect()

    def update(self):
        self.rect.y+=10
        pygame.sprite.groupcollide(obstacles_sprite,invaders_bullet_sprite,False,True)

class Obstacles(pygame.sprite.Sprite):
    def __init__(self,colour,x,y):
        super(Obstacles,self).__init__()
        self.image=pygame.Surface([150,50])
        self.image.fill(colour)
        self.rect=self.image.get_rect()
        self.rect.x=x
        self.rect.y=y


pygame.init()   

screen_height=400
screen_width=700
screen=pygame.display.set_mode([screen_width,screen_height])


all_sprites=pygame.sprite.Group()
player_sprite=pygame.sprite.Group()
invaders_sprite=pygame.sprite.Group()
player_bullet_sprite=pygame.sprite.Group()
invaders_bullet_sprite=pygame.sprite.Group()
obstacles_sprite=pygame.sprite.Group()

player=Player(BLUE)
player_sprite.add(player)
all_sprites.add(player)

obstacle=Obstacles(BLACK,50,300)
obstacle1=Obstacles(BLACK,275,300)
obstacle2=Obstacles(BLACK,500,300)
obstacles_sprite.add(obstacle,obstacle1,obstacle2)
all_sprites.add(obstacle,obstacle1,obstacle2)

player.rect.x=100
player.rect.y=375

for i in range(10):
    for x in range(3):### create grid for space invaders and draw
        invader=Invader(BLACK)
        invader.rect.x=50*i
        invader.rect.y=25*x
        invaders_sprite.add(invader)
        all_sprites.add(invader)

while not Done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Done = True

        if event.type==pygame.KEYDOWN:
            if event.key==pygame.K_SPACE:#### if space then create and fire bullet
                bullet=Player_bullet(BLACK)
                bullet.rect.x=player.rect.centerx
                bullet.rect.y=player.rect.y
                if len(player_bullet_sprite)<1:
                    player_bullet_sprite.add(bullet)
                    all_sprites.add(bullet)

    if event.type==pygame.KEYDOWN:
        if event.key==pygame.K_LEFT:
            player.rect.x-=5
        elif event.key==pygame.K_RIGHT:
            player.rect.x+=5


    for bullet in player_bullet_sprite: #####if bullet goes offscreen delete, 1 at a time
        hit=pygame.sprite.spritecollide(bullet,invaders_sprite,True)#kill invader, PROBLEM....

        for invaders_sprite in hit:
            player_bullet_sprite.remove(bullet)
            all_sprites.remove(bullet)

        if bullet.rect.y<0:
            player_bullet_sprite.remove(bullet)
            all_sprites.remove(bullet)

    for invader in invaders_sprite:##PROBLEM
        if player.rect.x==invader.rect.x: ### if invader is same x as player fire, 1
            if len(invaders_bullet_sprite)<1:
                invader_bullet=Invader_bullet(RED)
                invader_bullet.rect.x=invader.rect.centerx
                invader_bullet.rect.y=invader.rect.y
                invaders_bullet_sprite.add(invader_bullet)
                all_sprites.add(invader_bullet)

    for invader_bullet in invaders_bullet_sprite: ## remove if bullet offscreen
        pygame.sprite.spritecollide(invader_bullet,player_sprite,True)## check collision, kill player
        if invader_bullet.rect.y>screen_height:
            invaders_bullet_sprite.remove(invader_bullet)
            all_sprites.remove(invader_bullet)







    all_sprites.update()
    screen.fill(WHITE)
    all_sprites.draw(screen)
    pygame.display.flip()
    clock.tick(60)

Solution

  • You are overwriting invaders_sprites value at for invaders_sprite in hit. This means that invaders_sprite no longer refers to a sprite group which could be iterable.

    Try to split your program into smaller functions and avoid modifying global variables.