What should I do in order to create multiple instances of enemies?

Viewed 45

As a beginner, I am struggling to create multiple enemies in pygame. What could I possibly add or implement to my code in order to do so?

Code:

# WORK IN PROGRESS!
# I followed techwithtim's tutorial
# I do not own the images and sounds used in game
# TODO Create multiple Enemies
import pygame
import random


# Screen parameters
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("SPPACCE")
bg = pygame.image.load("bg.png")
font = pygame.font.SysFont('comicsans', 30, True)
clock = pygame.time.Clock()
score = 0

# Music & Sound effects
bulletsound = pygame.mixer.Sound('sounds/bullet_soundeffect.wav') 
explosion = pygame.mixer.Sound('sounds/explosion_effect.wav')
explosion2 = pygame.mixer.Sound('sounds/torpedo_explosion.wav')

# Player parameters
class Player(object):
    def __init__(self, x, y, height, width):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.player_vel = 5

    def draw(self, screen):
        screen.blit(player_char, (self.x, self.y))
       

# Enemy parameters
class Enemy(object):
    def __init__(self, x, y, height, width, end):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.enemy_vel = 1.5
        self.end = end   
        self.path = [self.x, self.end]
        self.hitbox = (self.x + 17, self.y + 2, 65, 65)
        self.health = 5
        self.visible = True


    def draw(self, screen):
        self.move()
        if self.visible:
            self.hitbox = (self.x + 0, self.y, 65, 65)
            pygame.draw.rect(screen, (255, 0, 0), self.hitbox, 2)
            screen.blit(enemy_char, (self.x, self.y))

            # Health bars
            pygame.draw.rect(screen, (0, 0, 0), (self.hitbox[0], self.hitbox[1] - 20, 65, 7))
            pygame.draw.rect(screen, (255, 0, 0), (self.hitbox[0], self.hitbox[1] - 20, 65 - (12 * (5 - self.health)), 7))                

    
    def move(self):
        if self.enemy_vel > 0:
            if self.x < self.path[1] + self.enemy_vel:
                self.x += self.enemy_vel
            else:
                self.enemy_vel = self.enemy_vel * -1
                self.x += self.enemy_vel
        else:
            if self.x > self.path[0] - self.enemy_vel:
                self.x += self.enemy_vel
            else:
                self.enemy_vel = self.enemy_vel * -1
                self.x += self.enemy_vel

    def hit(self):
        if self.health > 0:
            self.health -= 1
        else: 
            self.visible = False
            explosion.play()
            global score
            score += 1    
   
# Player Projectile parameters
class Projectile(object):
    def __init__(self, x, y, color, radius):
        self.x = x
        self.y = y
        self.color = color
        self.radius = radius
        self.vel = 12.5
    
    def draw(self, screen):
        pygame.draw.circle(screen, self.color, (self.x, self.y), self.radius)


# Images
player_char = pygame.image.load('sprites/hotdog.png')
enemy_char = pygame.image.load('sprites/hamburger.png')

def blit(): # This draws the sprites
    player.draw(screen)
    enemy.draw(screen)
    for projectile in projectiles:
        projectile.draw(screen)

    score_text = font.render("Score: " + str(score), 1, (0, 109, 255))
    version = font.render("Version 01 ", 1, (51, 153, 255))
    screen.blit(score_text, (0, 0))
    screen.blit(version, (520, 0))


shootloop = 0

if shootloop > 0:
    shootloop += 1
if shootloop > 2:
    shootloop = 0

player = Player(300, 400, 64, 64) 
enemy = Enemy(random.randint(10, 100), random.randint(20, 100), 64, 64, 480)
enemy_count = random.randint(1, 10)
projectiles = []
run = True


while run:
    clock.tick(60)
    screen.fill((0, 0, 0))
    screen.blit(bg, (0, 0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    # Movement keys with playeborders
    keys = pygame.key.get_pressed()
    if keys[pygame.K_s] and player.y < 480 - player.height - player.player_vel:
        player.y += player.player_vel
    if keys[pygame.K_w] and player.y > 280:
        player.y -= player.player_vel
    if keys[pygame.K_d] and player.x < 640 - player.width - player.player_vel:
        player.x += player.player_vel
    if keys[pygame.K_a] and player.x > player.player_vel:
        player.x -= player.player_vel
    

    for projectile in projectiles:
        if projectile.y - projectile.radius < enemy.hitbox[1] + enemy.hitbox[3] and projectile.y + projectile.radius > enemy.hitbox[1]:
            if enemy.visible == True:
                if projectile.x + projectile.radius > enemy.hitbox[0] and projectile.x - projectile.radius < enemy.hitbox[0] + enemy.hitbox[2]:
                    enemy.hit()
                    explosion2.play()
                    projectiles.pop(projectiles.index(projectile))
                    
        if projectile.y < 640 and projectile.y > 0:
            projectile.y -= projectile.vel
            
        else:
            projectiles.pop(projectiles.index(projectile))
    
    # Player shooting
    if keys[pygame.K_SPACE] and shootloop == 0:
        if len(projectiles) < 1:
            projectiles.append(Projectile(round(player.x + player.width //2), 
            round(player.y + player.height //2), [255, 150, 0], 7))
    
    blit()
    pygame.display.update()

I tried to recycle code from my last game project, but it doesn't work because the code structures are way too different from each other. This project is OOP meanwhile the last one has scattered variables.

1 Answers

Similar to your projectiles make a list of Enemy objects:

enemies = []
enemy_count = random.randint(3, 10)
for i in range( enemy_count ):
    new_enemy = Enemy(random.randint(10, 100), random.randint(20, 100), 64, 64, 480)
    enemies.append( new_enemy )
projectiles = []

Update your blit() to draw a list of enemies:

def blit(): # This draws the sprites
    player.draw(screen)
    for enemy in enemies:
        enemy.draw(screen)
    for projectile in projectiles:
        projectile.draw(screen)

    score_text = font.render("Score: " + str(score), 1, (0, 109, 255))
    version = font.render("Version 01 ", 1, (51, 153, 255))
    screen.blit(score_text, (0, 0))
    screen.blit(version, (520, 0))

And check them all for collisions:

for enemy in enemies:
    for projectile in projectiles:
        if projectile.y - projectile.radius < enemy.hitbox[1] + enemy.hitbox[3] and projectile.y + projectile.radius > enemy.hitbox[1]:
            if enemy.visible == True:
                if projectile.x + projectile.radius > enemy.hitbox[0] and projectile.x - projectile.radius < enemy.hitbox[0] + enemy.hitbox[2]:
                    enemy.hit()
                    explosion2.play()
                    projectiles.pop(projectiles.index(projectile))

That should get you started.

The changes are relatively simple because you already have the data compartmentalised in objects. Good job.

EDIT: Re-spawning an enemy is simply a matter of adding another Enemy object to the enemies list:

new_enemy = Enemy(random.randint(10, 100), random.randint(20, 100), 64, 64, 480)
enemies.append( new_enemy )
Related