-1

There are two problems with my code (I don't know if they're related).

Problem 1: The zombies sometimes don't die when they're shot and instead just remain unphased.

Problem 2: The Master Zombie bugs out after one hit and It doesn't move or appear but is still there (I can tell as it kills the player.

There is no event handler for when the health goes to 0, but I will add that later.

Here is the code:

import pygame
import sys
import math
from math import sin, cos
import random
from random import randint

pygame.init()

screen_width = 800
screen_height = 800

resolution = 64

scale_factor = screen_width / resolution

screen = pygame.display.set_mode((screen_width, screen_height))
screen_rect = screen.get_rect(topleft = (0, 0))
screen_mask = pygame.mask.from_surface(screen)

pygame.display.set_caption("Endless Onslaught")

icon = pygame.image.load("player.png").convert_alpha()
icon = pygame.transform.rotate(icon, 90)
pygame.display.set_icon(icon)

clock = pygame.time.Clock()

gunshot = pygame.mixer.Sound("gunshot.wav")
gunshot.set_volume(0.7)

empty_ammo_sound = pygame.mixer.Sound("empty_ammo.wav")



class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load("player.png").convert_alpha()
        self.image = pygame.transform.scale(self.image, (int(self.image.get_width()*2), int(self.image.get_height()*2)))
        self.original_image = self.image
        self.rect = self.image.get_rect(centerx = screen_width//2, centery = screen_height//2)
        self.mask = pygame.mask.from_surface(self.image)

        self.rotation = 0
        self.rotating_left = False
        self.rotating_right = False

        self.moving_forwards = False
        self.moving_backwards = False
        self.dx = 0
        self.dy = 0 
        

    
        

    def update(self):
        if self.rotating_left:
            self.rotation += 3.5
        elif self.rotating_right:
            self.rotation -= 3.5
            
        speed = 4
        
        self.dx = cos(math.radians(self.rotation)) 
        self.dy = sin(math.radians(self.rotation)) 

        if self.moving_forwards:  
            self.rect.x += self.dx * speed
            self.rect.y -= self.dy * speed


        elif self.moving_backwards:
            self.dx = cos(math.radians(self.rotation)) 
            self.dy = sin(math.radians(self.rotation))
            self.rect.x -= self.dx * speed
            self.rect.y += self.dy * speed

        if self.rect.centerx <= 0:
            self.rect.centerx = 0
        elif self.rect.centerx >= screen_width:
            self.rect.centerx = screen_width
        elif self.rect.centery <= 0:
            self.rect.centery = 0
        elif self.rect.centery >= screen_height:
            self.rect.centery = screen_height

        


        

        self.image = pygame.transform.rotate(self.original_image, self.rotation)
        self.rect = self.image.get_rect(centerx = self.rect.centerx, centery = self.rect.centery)
        self.mask = pygame.mask.from_surface(self.image)
    def spawn(self):
        player_group.add(self)

    def despawn(self):
        player_group.remove(self)
        
    def shoot(self):
        bullet = Bullet(self.rect.centerx,self.rect.centery, self.dx, self.dy, self.rotation)        
        bullet.spawn()
        pygame.mixer.Sound.play(gunshot)
        self.rect.x -= self.dx * 2
        self.rect.y += self.dy * 2
        ammo_bar.ammo -= 1
        

        

class Bullet(pygame.sprite.Sprite):
    def __init__ (self, x, y, dx, dy, rotation):
        super().__init__()
        self.image = pygame.image.load("bullet.png").convert_alpha()
        self.image = pygame.transform.scale(self.image, (int(self.image.get_width()*1.6), int(self.image.get_height()*1.6)))
        self.image = pygame.transform.rotate(self.image, rotation)
        self.rect = self.image.get_rect(centerx=x, centery=y)
        self.mask = pygame.mask.from_surface(self.image)
        self.dx = dx
        self.dy = dy
        
    

    def spawn(self):
        bullet_group.add(self)

    def despawn(self):
        bullet_group.remove(self)

class Zombie(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load("zombie.png").convert_alpha()
        self.image = pygame.transform.scale(self.image, (int(self.image.get_width()*1.8), int(self.image.get_height()*1.8)))
        self.original_image = self.image
        posx = random.choice([randint(-50, -5), randint(805, 850)])
        posy = random.choice([randint(-50, -5), randint(805, 850)])
        self.rect = self.image.get_rect(centerx=posx, centery= posy)
        self.mask = pygame.mask.from_surface(self.image)

    def update(self):
        distance = math.sqrt((self.rect.x - player.rect.x) ** 2 + (self.rect.y - player.rect.y) ** 2)

        if distance > 0:
            self.rect.x += (player.rect.x - self.rect.x) / distance
            self.rect.y += (player.rect.y - self.rect.y) / distance

        rotation = math.atan2(player.rect.y - self.rect.y, player.rect.x - self.rect.x)
        self.image = pygame.transform.rotate(self.original_image, -math.degrees(rotation))
        self.mask = pygame.mask.from_surface(self.image)
        
            
    def spawn(self):
        zombie_group.add(self)

    def despawn(self):
        zombie_group.remove(self)

class MasterZombie(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load("master_zombie.png").convert_alpha()
        self.image = pygame.transform.scale(self.image, (int(self.image.get_width()*3), int(self.image.get_height()*3)))
        self.original_image = self.image
        posx = random.choice([randint(-50, -5), randint(805, 850)])
        posy = random.choice([randint(-50, -5), randint(805, 850)])
        self.rect = self.image.get_rect(centerx=posx, centery= posy)
        self.mask = pygame.mask.from_surface(self.image)
        self.hp = 5

    def update(self):
        distance = math.sqrt((self.rect.x - player.rect.x) ** 2 + (self.rect.y - player.rect.y) ** 2)

        if distance > 0:
            self.rect.x += 3*(player.rect.x - self.rect.x) / distance
            self.rect.y += 3*(player.rect.y - self.rect.y) / distance

        rotation = math.atan2(player.rect.y - self.rect.y, player.rect.x - self.rect.x)
        self.image = pygame.transform.rotate(self.original_image, -math.degrees(rotation))
        self.mask = pygame.mask.from_surface(self.image)
        
            
    def spawn(self):
        master_zombie_group.add(self)

    def despawn(self):
        master_zombie_group.remove(self)

class HealthBar(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.full_health_bar = pygame.image.load("full_health_bar.png").convert_alpha()
        self.full_health_bar = pygame.transform.scale(self.full_health_bar, (int(self.full_health_bar.get_width()*1.3), int(self.full_health_bar.get_height()*1.3)))
        self.full_health_bar_rect = self.full_health_bar.get_rect(topleft = (10, 5))
        
        self.empty_health_bar = pygame.image.load("empty_health_bar.png").convert_alpha()
        self.empty_health_bar = pygame.transform.scale(self.empty_health_bar, (int(self.empty_health_bar.get_width()*1.3), int(self.empty_health_bar.get_height()*1.3)))
        self.empty_health_bar_rect = self.empty_health_bar.get_rect(topleft = (10, 5))
        
        self.hp = 5
        self.max_hp = 5

    def draw(self):
        ratio = self.hp / self.max_hp       
        remaining_width = int(self.full_health_bar.get_width() * ratio)
        self.health_bar = self.full_health_bar.copy().subsurface(pygame.Rect(0, 0, remaining_width, self.full_health_bar.get_height()))
        
        screen.blit(self.empty_health_bar, self.empty_health_bar_rect)
        screen.blit(self.health_bar, self.full_health_bar_rect)

class AmmoBar(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.full_ammo_bar = pygame.image.load("full_ammo_bar.png").convert_alpha()
        self.full_ammo_bar = pygame.transform.scale(self.full_ammo_bar, (int(self.full_ammo_bar.get_width()*3.5), int(self.full_ammo_bar.get_height()*3.5)))
        self.full_ammo_bar_rect = self.full_ammo_bar.get_rect(topright = (790, 5))
        
        self.empty_ammo_bar = pygame.image.load("empty_ammo_bar.png").convert_alpha()
        self.empty_ammo_bar = pygame.transform.scale(self.empty_ammo_bar, (int(self.empty_ammo_bar.get_width()*3.5), int(self.empty_ammo_bar.get_height()*3.5)))
        self.empty_ammo_bar_rect = self.empty_ammo_bar.get_rect(topright = (790, 5))
        
        self.ammo = 25
        self.max_ammo = 25

    def draw(self):
        ratio = self.ammo / self.max_ammo       
        remaining_width = int(self.full_ammo_bar.get_width() * ratio)
        self.ammo_bar = self.full_ammo_bar.copy().subsurface(pygame.Rect(0, 0, remaining_width, self.full_ammo_bar.get_height()))
        
        screen.blit(self.empty_ammo_bar, self.empty_ammo_bar_rect)
        screen.blit(self.ammo_bar, self.full_ammo_bar_rect)

class Ammo(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load("bullet.png").convert_alpha()
        self.image = pygame.transform.scale(self.image, (int(self.image.get_width()*3), int(self.image.get_height()*3)))
        self.image = pygame.transform.rotate(self.image, 90)
        posx = randint(0, 800)
        posy = randint(50, 800)
        self.rect = self.image.get_rect(centerx = posx, centery = posy)
        self.mask = pygame.mask.from_surface(self.image)

    def spawn(self):
        ammo_group.add(self)

    def despawn(self):
        ammo_group.remove(self)

class GreenGun(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.image.load("green_gun.png").convert_alpha()
        self.image = pygame.transform.scale(self.image, (int(self.image.get_width()*3), int(self.image.get_height()*3)))
        self.rect = self.image.get_rect(centerx = x, centery = y)
        self.mask = pygame.mask.from_surface(self.image)

    def spawn(self):
        green_gun_group.add(self)

    def despawn(self):
        green_gun_group.remove(self)

class RedGun(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.image.load("red_gun.png").convert_alpha()
        self.image = pygame.transform.scale(self.image, (int(self.image.get_width()*3), int(self.image.get_height()*3)))
        self.rect = self.image.get_rect(centerx = x, centery = y)
        self.mask = pygame.mask.from_surface(self.image)

    def spawn(self):
        red_gun_group.add(self)

    def despawn(self):
        red_gun_group.remove(self)
        

    
    
        
    
            

player_group = pygame.sprite.Group()
player = Player()
player.spawn()

bullet_group = pygame.sprite.Group()

zombie_group = pygame.sprite.Group()
master_zombie_group = pygame.sprite.Group()

zombies = [Zombie() for i in range(0, 35)]

zombies[0].spawn()

ammo_group = pygame.sprite.Group()
ammo = Ammo()
ammo.spawn()


health_bar = HealthBar()
ammo_bar = AmmoBar()

green_gun_group = pygame.sprite.Group()
red_gun_group = pygame.sprite.Group()

background = pygame.image.load("background.jpg").convert()
background = pygame.transform.scale(background, (int(background.get_width()*scale_factor * 2), int(background.get_height()*scale_factor * 2)))
background_rect = background.get_rect(topleft = (0, 0))

def game():
    score = 0
    zombie_spawning_cooldown = randint(3, 7)
    zombie_index = 1
    shot_fired = False
    running = True
    bullet_cooldown= 0
    ammo_collected = False
    green_gun_collected = True
    red_gun_collected = True
    gun_state = "normal"
    master_zombie_spawned = False
    master_zombie_cooldown = 0
    while running:
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_a:
                    player.rotating_left = True
                elif event.key == pygame.K_d:
                    player.rotating_right = True
                if event.key == pygame.K_w:
                    player.moving_forwards = True
                elif event.key == pygame.K_s:
                    player.moving_backwards = True
                elif event.key == pygame.K_SPACE and bullet_cooldown <= 0:
                    if not shot_fired:
                        shot_fired = True
                    if ammo_bar.ammo > 0:
                        player.shoot()
                        if gun_state == "green":
                            bullet_cooldown = 10
                        else:
                            bullet_cooldown = 20
                    else:
                        pygame.mixer.Sound.play(empty_ammo_sound)
                    
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_a:
                    player.rotating_left = False
                elif event.key == pygame.K_d:
                    player.rotating_right = False
                if event.key == pygame.K_w:
                    player.moving_forwards = False
                elif event.key == pygame.K_s:
                    player.moving_backwards = False

            elif event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1 and bullet_cooldown <= 0:
                    if not shot_fired:
                        shot_fired = True
                    if ammo_bar.ammo > 0:
                        player.shoot()
                        if gun_state == "green":
                            bullet_cooldown = 10
                        else:
                            bullet_cooldown = 20
                    else:
                        pygame.mixer.Sound.play(empty_ammo_sound)
                    

        if bullet_cooldown > 0:
            bullet_cooldown -= 1 

        if gun_state == "green":
            player.image = pygame.image.load("player_green_gun.png").convert_alpha()
            player.image = pygame.transform.scale(player.image, (int(player.image.get_width()*2), int(player.image.get_height()*2)))
            player.original_image = player.image
            ammo_bar.max_ammo = 35
        elif gun_state == "red":
            player.image = pygame.image.load("player_red_gun.png").convert_alpha()
            player.image = pygame.transform.scale(player.image, (int(player.image.get_width()*2), int(player.image.get_height()*2)))
            player.original_image = player.image
            ammo_bar.max_ammo = 25
        else:
            player.image = pygame.image.load("player.png").convert_alpha()
            player.image = pygame.transform.scale(player.image, (int(player.image.get_width()*2), int(player.image.get_height()*2)))
            player.original_image = player.image
            ammo_bar.max_ammo = 25
            
            

        for bullet in bullet_group:
            speed = 10

            bullet.rect.x += bullet.dx * speed
            bullet.rect.y -= bullet.dy * speed

            if bullet.rect.right < 0 or bullet.rect.left > screen_width or bullet.rect.bottom < 0 or bullet.rect.top > screen_height:
                bullet.despawn()

        for zombie in zombie_group:
            zombie.update()

            if zombie.mask.overlap(player.mask, (player.rect.x - zombie.rect.x, player.rect.y - zombie.rect.y)):
                zombie.rect.centerx = random.choice([randint(-50, -5), randint(805, 850)])
                zombie.rect.centery = random.choice([randint(-50, -5), randint(805, 850)])
                health_bar.hp -=1
                           
            if shot_fired:
                if bullet.mask.overlap(zombie.mask, (zombie.rect.x - bullet.rect.x, zombie.rect.y - bullet.rect.y)):
                    if score > 10:
                         chance_of_drop = randint(0, 5)
                         if chance_of_drop == 0 and green_gun_collected and gun_state != "green":
                             green_gun = GreenGun(zombie.rect.centerx, zombie.rect.centery)
                             green_gun.spawn()
                             green_gun_collected = False
                         elif chance_of_drop == 1 and red_gun_collected and gun_state != "red" and score > 15:
                             red_gun = RedGun(zombie.rect.centerx, zombie.rect.centery)
                             red_gun.spawn()
                             red_gun_collected = False
                                                 
                                                   
                    score += 1
                    if gun_state != "red":
                        bullet.despawn() 
                    zombie.rect.centerx = random.choice([randint(-50, -5), randint(805, 850)])
                    zombie.rect.centery = random.choice([randint(-50, -5), randint(805, 850)])
                    zombie_spawning_cooldown -=1 
                    if zombie_index <= 34 and zombie_spawning_cooldown <= 0:
                        zombies[zombie_index].spawn()
                        zombie_index += 1
                        zombie_spawning_cooldown = randint(3, 7)
        if shot_fired:
                        
            if score >= 0 and master_zombie_cooldown <= 0 and not master_zombie_spawned:
                master_zombie = MasterZombie()
                master_zombie.spawn()
                master_zombie_cooldown = randint(1000, 2000)
                master_zombie_spawned = True

            if master_zombie.mask.overlap(player.mask, (player.rect.x - master_zombie.rect.x, player.rect.y - master_zombie.rect.y)):
                master_zombie.despawn()
                master_zombie_cooldown = randint(1000, 2000)
                health_bar.hp -= 5

            if bullet.mask.overlap(master_zombie.mask, (master_zombie.rect.x - bullet.rect.x, master_zombie.rect.y - bullet.rect.y)):
                bullet.despawn()
                master_zombie.hp -= 1
                 
            if master_zombie.hp == 0:
                master_zombie.despawn()
                master_zombie_cooldown = randint(1000, 2000)  
                score += 5
                             
                             
                    
                        
        for ammo in ammo_group:
            if ammo.mask.overlap(player.mask, (player.rect.x - ammo.rect.x, player.rect.y - ammo.rect.y)):
                ammo.despawn()
                ammo_collected = True
                if ammo_bar.ammo <= 25:
                    ammo_bar.ammo += 1

            if ammo_collected:
                ammo = Ammo()
                ammo.spawn()
                ammo_collected = False
                
        for green_gun in green_gun_group:
            if green_gun.mask.overlap(player.mask, (player.rect.x - green_gun.rect.x, player.rect.y - green_gun.rect.y)):
                green_gun.despawn()
                green_gun_collected = True
                gun_state = "green"

        for red_gun in red_gun_group:
            if red_gun.mask.overlap(player.mask, (player.rect.x - red_gun.rect.x, player.rect.y - red_gun.rect.y)):
                red_gun.despawn()
                red_gun_collected = True
                gun_state = "red"
            
                
        screen.blit(background, background_rect)
        
        player.update()
        player_group.draw(screen)

        ammo_group.draw(screen)

        green_gun_group.draw(screen)
        red_gun_group.draw(screen)

        zombie.update()
        zombie_group.draw(screen)
        
        if master_zombie_spawned:
            master_zombie.update()
            master_zombie_group.draw(screen)
        
        bullet_group.draw(screen)

        health_bar.draw()
        ammo_bar.draw()
        
        pygame.display.flip()
        clock.tick(60)
        
    pygame.quit()
    sys.exit()

game()

The game is meant to be an endless zombie shooter, with master zombies that occasionally spawn and take 5 hits to die and also deal 5x more damage. However, they just bug out and don't update or appear after one shot.

TAB5432
  • 1
  • 2

0 Answers0