Search code examples
pythonpygamecollision-detection

Trying to spawn multiple enemies for my game in pygame


I'm trying to spawn multiple enemies in my space invader type game but I have not had any luck. I have tried appending to lists in a few different ways but have been unsuccessful. I also don't want to create multiple characters but want to spawn different versions of the same one. I don't mind whether it is a set number of enemies or enemies spawning every couple of seconds. This is my code so far:

import pygame 
import sys
import random
pygame.init()

#window of game
window = pygame.display.set_mode((550,550))

#character image 
character = pygame.image.load('gg/New Piskel-1.png.png')

clock = pygame.time.Clock()

score = 0

# character
class player(object):
  def __init__(self, x, y, width, height):
    self.x = x 
    self.y = y 
    self.width = width
    self.height = height
    self.speed = 5 
    self.hitbox = (self.x + 10, self.y + 15, 33, 43)
    self.health = 10
    self.visible = True
  
  def draw(self , window):
    if self.visible == True:
      if left:
        window.blit(character, (self.x ,self.y))
      elif right:
        window.blit(character, (self.x,self.y))
      elif up:
        window.blit(character, (self.x,self.y))
      elif down:
        window.blit(character, (self.x,self.y))
      else:
        window.blit(character, (self.x,self.y))
    self.hitbox = (self.x + 10, self.y + 15, 33, 43)

    if self.visible == False:
     font_display = pygame.font.SysFont('comicsans', 100)
     text = font_display.render('YOU ARE DEAD' , 1 , (255, 0, 0))
     window.blit(text , (275 - (text.get_width()/2), 275))
     pygame.display.update()
    #pygame.draw.rect(window , (255, 0 , 0), self.hitbox , 2) # hitbox
  pygame.display.update()

  def hit(self):
    if self.health > 0:
      self.health -=  1 
    else:
      self.visible = False
      font_display = pygame.font.SysFont('comicsans', 100)
      text = font_display.render('YOU ARE DEAD' , 1 , (255, 0, 0))
      window.blit(text , (275 - (text.get_width()/2), 275))
      pygame.display.update()
    


class shot(object):
  def __init__(self  , x , y , radius,  color):
    self.x = x 
    self.y = y
    self.radius = radius
    self.color = color
    self.speed = 10
  
  def draw(self , window):
    pygame.draw.circle(window, self.color ,(self.x , self.y), self.radius)


class enemy(object):
  enemy_img = pygame.image.load('gg/alien.png')

  def __init__(self  , x , y , width , height , end):
    self.x = x
    self.y = y
    self.width = width
    self.height = height
    self.end = end
    self.speed = 1
    self.path = [self.y , self.end]
    self.hitbox = (self.x + 7, self.y, 13, 20)
    self.health = 14
    self.visible = True

  def draw(self, window):
    self.move()
    if self.y > 548:
      self.visible = False  


    if self.visible:
      if self.speed > 0:
        window.blit(self.enemy_img, (self.x , self.y))
      pygame.draw.rect(window, (255, 0, 0), (self.hitbox[0], self.hitbox[1] - 20, 14 , 10))
      pygame.draw.rect(window, (0, 255, 0), (self.hitbox[0], self.hitbox[1] - 20, 14 - ((14/7) * (14 - self.health)) , 10))
      self.hitbox = (self.x + 7, self.y, 13, 20)
    pygame.draw.rect(window , (255, 0 , 0), self.hitbox , 2)# hitbox
  


  def move(self):
    if self.y + self.speed < self.path[1]:
      self.y += self.speed

  
  def hit(self):
    if self.health > 0:
      self.health -= 2
    else:
      self.visible = False
      print('hit')


begin = True

bullets  = []
enemy_list = []



#animation/character display
def drawing_window():
  window.fill((0,0,0))
  text = font.render('Score: ' + str(score), 1, (255,0,0))
  window.blit(text, (390, 10))
  space_ship.draw(window)
  for bullet in bullets :
    bullet.draw(window)
  aliens.draw(window)
  pygame.display.update()


#movement and other repeating data (i.e bullets)
font = pygame.font.SysFont('comicsans', 30 , True)
space_ship = player(250 , 460 , 45 , 50)
aliens  = enemy(random.randint(10 , 540) , 200, 15 , 25 , 550 )

while begin:
  clock.tick(50)
  if aliens.visible == True:
    if space_ship.hitbox[1] < aliens.hitbox[1] + aliens.hitbox[3] and space_ship.hitbox[1] + space_ship.hitbox[3] > aliens.hitbox[1]:
      if space_ship.hitbox[0] + space_ship.hitbox[2] > aliens.hitbox[0] and space_ship.hitbox[0] < aliens.hitbox[0]  + aliens.hitbox[2]:
        space_ship.hit()
     
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
      run = False
  for bullet in bullets:
    if aliens.visible == True:
      if bullet.y - bullet.radius < aliens.hitbox[1] + aliens.hitbox[3] and bullet.y + bullet.radius > aliens.hitbox[1]:
        if bullet.x + bullet.radius > aliens.hitbox[0] and bullet.x - bullet.radius < aliens.hitbox[0]  + aliens.hitbox[2]:
         aliens.hit()
         score += 1
         bullets.pop(bullets.index(bullet))

    if bullet.y > 0:
      bullet.y = bullet.y - 10
    else:
      bullets.pop(bullets.index(bullet))  
  keys = pygame.key.get_pressed()
  if keys[pygame.K_SPACE]:
    if len(bullets) < 11:
      bullets.append(shot(round(space_ship.x + space_ship.width //2), round(space_ship.y + space_ship.height//2), 3 , (255,0,0,)))
  if  keys[pygame.K_LEFT] and space_ship.x > space_ship.speed:
    space_ship.x -= space_ship.speed
    left = True
    right = False
    up = False
    down = False
  elif  keys[pygame.K_RIGHT] and space_ship.x < 550 - space_ship.width -space_ship.speed:
    space_ship.x += space_ship.speed
    left = False
    right = True
    up = False
    down = False
  if  keys[pygame.K_UP] and space_ship.y > space_ship.speed:
    up = True
    down = False
    left = False
    right = False
    space_ship.y -= space_ship.speed
  if  keys[pygame.K_DOWN] and space_ship.y <550 - space_ship.height - space_ship.speed:
    up = False 
    down = True
    left = False
    right = False
    space_ship.y += space_ship.speed
  else:
   left = False
   right = False
   up = False
   down = False 
  drawing_window()

  

pygame.quit()

Solution

  • Remove the variable aliens, but add the enemies to the enemy_list. You can add multiple enemies:

    no_of_enemies = 3
    for _ in range(no_of_enemies): 
        x = None
        while (x == None or any(enemy_rect.colliderect(e.hitbox) for e in enemy_list)):
            x = random.randint(10 , 540)
            enemy_rect = pygame.Rect(x , 200, 15 , 25)
        enemy_list.append(enemy(x, 200, 15, 25, 550))
    

    Draw all the enemies in the list in a loop:

    #animation/character display
    def drawing_window():
        window.fill((0,0,0))
        text = font.render('Score: ' + str(score), 1, (255,0,0))
        window.blit(text, (390, 10))
        space_ship.draw(window)
        for bullet in bullets:
            bullet.draw(window)
        for aliens in enemy_list:
           aliens.draw(window)
        pygame.display.update()
    

    Do the collision test in (nested) loops. DO not iterate the list, but shallow cpies of the lists (see How to remove items from a list while iterating?).
    Use pygame.Rect.colliderect to detect the collision (see How do I detect collision in pygame?):

    while begin:
      clock.tick(50)
      ship_rect = pygame.Rect(space_ship.hitbox)
      for aliens in enemy_list[:]:
            if ship_rect.colliderect(aliens.hitbox):
                space_ship.hit()
         
      for event in pygame.event.get():
            if event.type == pygame.QUIT:
                begin = False
      
      for bullet in bullets[:]:
            if bullet.y > 0:
    
                for aliens in enemy_list[:]:
                    bullet_rect = pygame.Rect(0, 0, bullet.radius*2, bullet.radius*2)
                    bullet_rect.center = (bullet.x, bullet.y)
                    if bullet_rect.colliderect(aliens.hitbox):
                        score += 1
                        bullets.remove(bullet)
                        aliens.hit()
                        if aliens.health <= 0:
                            enemy_list.remove(aliens)
    
                bullet.y = bullet.y - 10
    
            else:
                bullets.remove(bullet) 
    
      # [...]