0

I am teaching myself python 3, and creating a python based game using pygame but am running into two problems.

In order to post here, I stripped my game down to the bare minimum but there is still quite a bit and I apologize for that. You have to actually be able to run my game to see the problem, so the below is the minimum required code to duplicate the problem. I stripped out all non essentials, walls, weapons, types of characters and images and replaced them with blocks so you can just copy, paste, and run it in Python 3.

This game is a "survive each round" type game.

Every level, there should be more enemy's allowed on the screen at a time. When the player shoots them, they are removed, but another one spawns to take its place.

I have 2 main problems.

  1. The only parts of my code that currently (should be) removing enemy sprites from the sprites list, is if they get shot by the player, or they make contact with the player. About every 20 enemy's or so, one will simply disappear and I can't figure out why.

  2. To the best of my knowledge, I have the enemy spawn set so that they will only spawn if they are at least 500 pixels away in any direction, yet they still will occasionally spawn on top of the player.

The best way to replicate these is playing the first few levels, and watch specifically for enemy's disappearing or spawning super close. It seems to be rng so it may take a few attempts.

I included notes in the code to attempt to save you from having to scan the whole thing.

import pygame,math,random,sys
#Colors
black       = (0,0,0)
white       = (255,255,255)
red         = (188,13,13)
orange      = (188,13,13)
yellow      = (188,188,13)
green       = (101,188,13)
blue_green  = (13,188,100)
blue        = (13,101,188)
purple      = (100,13,188)
magenta     = (188,13,101)
background1 = (93,58,23)
texture_1_1 = (116,71,25)
texture_1_2 = (75,57,31)
texture_1_3 = (105,77,49)
class Elven_Arrow_up(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface([4,4])
        self.image.fill(black)
        self.rect = self.image.get_rect()
    def update(self):
        self.rect.y -= 4
class Elven_Arrow_down(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface([4,4])
        self.image.fill(black)
        self.rect = self.image.get_rect()
    def update(self):
        self.rect.y += 4
class Elven_Arrow_left(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface([4,4])
        self.image.fill(black)
        self.rect = self.image.get_rect()
    def update(self):
        self.rect.x -= 4
class Elven_Arrow_right(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface([4,4])
        self.image.fill(black)
        self.rect = self.image.get_rect()
    def update(self):
        self.rect.x += 4
class Player(pygame.sprite.Sprite):
    def __init__(self,health,speed, x, y):
        super().__init__()
        self.health = health
        self.speed = speed
        self.image = pygame.Surface([32,32])
        self.image.fill(blue)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.change_x = 0
        self.change_y = 0
    def changespeed(self, x, y):
        self.change_x += x
        self.change_y += y
    def update(self):
        self.rect.x += self.change_x
        self.rect.y += self.change_y
class Enemy (pygame.sprite.Sprite):
    def __init__(self,speed,health,points):
        super().__init__()
        self.image = pygame.Surface([32,32])
        self.image.fill(red)
        self.rect = self.image.get_rect()
        self.speed = speed
        self.health = health
        self.points = points
    def update(self):
        dirvect = pygame.math.Vector2(player.rect.x - self.rect.x,
                                      player.rect.y - self.rect.y)
        dirvect.normalize()
        dirvect.scale_to_length(self.speed)
        self.rect.move_ip(dirvect)
class GameState():
    def __init__(self):
        self.state = 'intro'
    def intro(self):
        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                done = True
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                self.state = 'level'
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    self.state = 'level'
        screen.fill(white)
        score_font = pygame.font.SysFont('Calibri', 25, True, False)
        score_text = score_font.render('Click the Space Bar to Begin.',True,black)
        screen.blit(score_text,(screen_width/2 - 180,screen_height/2 + 250))
        pygame.display.flip()
    def game_over(self):
        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                done = True
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                global enemy_list
                global all_sprites_list
                global player
                global score
                global max_num_of_enemies
                global level
                global score_needed
                global score_needed_constant
                global score_needed_add
                global score_needed_add_constant
                max_num_of_enemies = max_num_of_enemies_constant
                enemy_list = pygame.sprite.Group()
                all_sprites_list = pygame.sprite.Group()
                player = Player(10,3,screen_width/2-3,screen_width/2,cinder_image)
                all_sprites_list.add(player)
                score_needed = score_needed_constant
                score_needed_add = score_needed_add_constant
                score = 0
                self.state = 'intro'
        screen.fill(black)
        score_font = pygame.font.SysFont('Calibri', 25, True, False)
        score_text = score_font.render("Click to continue.",True,white)
        level_text = score_font.render("You got to Level: " + str(level),True,white)
        screen.blit(score_text,(screen_width/2 + 200,screen_height/2 + 350))
        screen.blit(level_text,(10,10))
        pygame.display.flip()

#Below this line ends the level, removes all sprites from display lists, and returns the player to the center of the screen
    def level_complete(self):
        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                done = True
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:    
                    global enemy_list
                    global all_sprites_list
                    global player
                    global score
                    global max_num_of_enemies
                    global max_num_of_enemies_constant
                    global level
                    enemy_list = pygame.sprite.Group()
                    all_sprites_list = pygame.sprite.Group()
                    all_sprites_list.add(player)
                    player.change_x = 0
                    player.change_y = 0
                    player.rect.x = screen_width/2
                    player.rect.y = screen_width/2
                    player.update()
                    self.state = 'level'
        screen.fill(blue)
        score_font = pygame.font.SysFont('Calibri', 25, True, False)
        continue_text = score_font.render("Release all keys, and Press the Spacebar to Continue.",True,white)
        level_text = score_font.render("You Completed level " + str(level-1) + "",True,white)
        screen.blit(continue_text,(50,screen_height - 30))
        screen.blit(level_text,(screen_width/2-100,screen_height/2))
        pygame.display.flip()
#Above this line ends the level, removes all sprites from display, and returns the player to the center of the screen

#Below this line is the main game loop.
    def level(self):
        global Enemy
        global enemy_list
        global score
        global player
        global all_sprites_list
        global max_num_of_enemies
        global level
        global score_needed
        global score_needed_add
        pygame.mouse.set_visible(1)
        
#Below this line spawns enemy's, if there are less enemy's than the max number of enemies AND they are far enough from the player
        if len(enemy_list.sprites()) < max_num_of_enemies: 
            x = random.randrange(-500,screen_width+500)
            y = random.randrange(-500,screen_height+500) 
            spawn = True
            for enemy in enemy_list:
                ex, ey = enemy.rect.center
                distance = math.hypot(ex - x, ey - y)
                if distance < minimum_distance: 
                    spawn = False
                    break
            if spawn:
                speed = 1.5
                health = 1
                points = 1
                enemy = Enemy(speed,health,points)
                enemy.rect.center = x, y
                enemy_list.add(enemy)
                all_sprites_list.add(enemy)
#Above this line spawns enemy's, if there are less enemy's than the max number of enemies AND they are far enough from the player

#Below this line determines when the level will end, increases the number of enemies allowed on the screen, and sends you to the level complete page
        if level < 1:
            level = 1
        elif score >= score_needed:
            level +=1
            max_num_of_enemies += 3
            score_needed += score_needed_add
            score_needed_add += 5
            player.health += 1
            self.state = 'level_complete'

#Above this line determines when the level will end, increases the number of enemies allowed on the screen, and sends you to the level complete page
        for event in pygame.event.get():
            if event.type == pygame.QUIT: 
                done = True
                pygame.quit()
                sys.exit()
            if player.health <= 0:
                self.state = 'game_over'
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_a:
                    player.changespeed(-3, 0)
                elif event.key == pygame.K_d:
                    player.changespeed(3, 0)
                elif event.key == pygame.K_w:
                    player.changespeed(0, -3)
                elif event.key == pygame.K_s:
                    player.changespeed(0, 3)
                elif event.key == pygame.K_LEFT:
                    projectile = Elven_Arrow_left()
                    projectile.rect.x = player.rect.x + 3
                    projectile.rect.y = player.rect.y + 8
                    projectile_list.add(projectile)
                    all_sprites_list.add(projectile)
                elif event.key == pygame.K_RIGHT:
                    projectile = Elven_Arrow_right()
                    projectile.rect.x = player.rect.x + 3
                    projectile.rect.y = player.rect.y + 8
                    projectile_list.add(projectile)
                    all_sprites_list.add(projectile)
                elif event.key == pygame.K_UP:
                    projectile = Elven_Arrow_up()
                    projectile.rect.x = player.rect.x + 3
                    projectile.rect.y = player.rect.y + 8
                    projectile_list.add(projectile)
                    all_sprites_list.add(projectile)
                elif event.key == pygame.K_DOWN:
                    projectile = Elven_Arrow_down()
                    projectile.rect.x = player.rect.x + 3
                    projectile.rect.y = player.rect.y + 8
                    projectile_list.add(projectile)
                    all_sprites_list.add(projectile)
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_a:
                    player.changespeed(3, 0)
                elif event.key == pygame.K_d:
                    player.changespeed(-3, 0)
                elif event.key == pygame.K_w:
                    player.changespeed(0, 3)
                elif event.key == pygame.K_s:
                    player.changespeed(0, -3)
        all_sprites_list.update()
        if player.rect.y > screen_height + 10:
            player.rect.y = -10
        elif player.rect.y < -10:
            player.rect.y = screen_height + 10
        if player.rect.x > screen_width + 10:
            player.rect.x = -10
        elif player.rect.x < -10:
            player.rect.x = screen_width + 10
            
#Below this line removes an enemy if they are shot by the player, and gives them a point
        for projectile in projectile_list:
            player_hit_list = pygame.sprite.spritecollide(projectile,enemy_list,True)
            for enemy in player_hit_list:
                projectile_list.remove(projectile)
                all_sprites_list.remove(projectile)
                score += 1
#Above this line removes an enemy if they are shot by the player, and gives them a point
                
            if projectile.rect.y < -10:
                projectile_list.remove(projectile)
                all_sprites_list.remove(projectile)
            elif projectile.rect.y > screen_height + 10:
                projectile_list.remove(projectile)
                all_sprites_list.remove(projectile)
            elif projectile.rect.x < -10:
                projectile_list.remove(projectile)
                all_sprites_list.remove(projectile)
            elif projectile.rect.x > screen_width + 10:
                projectile_list.remove(projectile)
                all_sprites_list.remove(projectile)
                
#Below this line removes an enemy if they make contact with the player.
        for block in enemy_list:
            enemy_hit_list = pygame.sprite.spritecollide(player, enemy_list, True)
            for block in enemy_hit_list:
                enemy_list.remove(block)
                all_sprites_list.remove(block)
                player.health -= block.points
#Above this line removes an enemy if they make contact with the player.

        screen.fill(background1)
        for i in texture_list1:
            texture1 = pygame.draw.rect(screen,texture_1_1,[i[0],i[1],10,10])
        for i in texture_list2:
            texture1 = pygame.draw.rect(screen,texture_1_2,[i[0],i[1],10,10])
        for i in texture_list3:
            texture1 = pygame.draw.rect(screen,texture_1_3,[i[0],i[1],10,10])    
        all_sprites_list.draw(screen)
        score_font = pygame.font.SysFont('Calibri', 25, True, False)
        score_text = score_font.render("Score: " + str(score),True,blue_green)
        noob_text = score_font.render("w,a,s,d to move, arrow keys to shoot. Good luck.",True,white)
        level_text = score_font.render("Level: " + str(level),True,blue_green)
        screen.blit(score_text,[10,10])
        screen.blit(level_text,[screen_width - 150,10])
        if score < 10:
            screen.blit(noob_text,[100,10])
        if player.health >= health_status[0]:
            health_text = score_font.render("Health: " + str(player.health),True,blue_green)
        elif player.health >= health_status[1]:
            health_text = score_font.render("Health: " + str(player.health),True,green)
        elif player.health >= health_status[2]:
            health_text = score_font.render("Health: " + str(player.health),True,yellow)
        elif player.health >= health_status[3]:
            health_text = score_font.render("Health: " + str(player.health),True,orange)
        elif player.health >= health_status[4]:
            health_text = score_font.render("Health: " + str(player.health),True,red)
        screen.blit(health_text, [10,40])
        pygame.display.flip()
#Above this line is the main game loop
        
    def state_manager(self):
        if self.state == 'intro':
            self.intro()
        if self.state == 'game_over':
            self.game_over()
        if self.state == 'level':
            self.level()
        if self.state == 'level_complete':
            self.level_complete()
pygame.init()
screen_width  = 1000
screen_height = 800
screen = pygame.display.set_mode([screen_width, screen_height])
game_state = GameState()
enemy_list = pygame.sprite.Group()
projectile_list = pygame.sprite.Group()
item_list = pygame.sprite.Group()
texture_list1 = []
texture_list2 = []
texture_list3 = []
all_sprites_list = pygame.sprite.Group()
player = Player(10,3,screen_width/2 - 3,screen_height/2)
all_sprites_list.add(player)
for i in range(50):
    x=random.randrange(screen_width)
    y=random.randrange(screen_width)
    texture_list1.append([x,y])
for i in range(50):
    x=random.randrange(screen_width)
    y=random.randrange(screen_width)
    texture_list2.append([x,y])
for i in range(50):
    x=random.randrange(screen_width)
    y=random.randrange(screen_width)
    texture_list3.append([x,y])
#Below this line sets the starting points, and constants through the game.
score = 0
health_status = (8,6,4,2,-100)
level = 1
minimum_distance = 500
score_needed_constant = 15
score_needed = score_needed_constant
score_needed_add_constant = 15
score_needed_add = score_needed_add_constant
max_num_of_enemies_constant = 8
max_num_of_enemies = max_num_of_enemies_constant
#Above this line sets the starting points, and constants through the game.

#Below this line starts, and ends the game loop
done = False
clock = pygame.time.Clock()
while not done:
    game_state.state_manager()
#Above this line starts, and ends the game loop

    clock.tick(60)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Where is the code that removes enemies? All your objects are [`pygame.sprite.Sprite`](https://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Sprite) objects. Why do you not just [`kill()`](https://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Sprite.kill) sprites and enemies? – Rabbid76 Nov 22 '20 at 08:23
  • @Rabbid76 sorry for the late reply, I marked the code with notes. I didn't know you could kill them, but i am removing them from the all sprites list and the enemy list when they make contact with the player or a projectile. Before then, they should always be shown. – Josh Stapley Nov 24 '20 at 19:30

0 Answers0