Search code examples
pythonpygameartificial-intelligenceplatform

I have been trying to have a new enemy spawn every 20 seconds using pygame


I have been trying to make my enemy spawn every 20 seconds to counteract the fact that the enemy gets stuck underneath platforms when it is directly bellow the player, I have left the method that I was going to use, however I have not had much luck implementing it.

The plan was to use the timer.tick built into python to be able to time every 20 seconds, however I realised that this just worked on the frame rate, as you can see at the top I used start = time.time() to begin the clock, and then write end = time.time() to end the clock after 20 seconds.

import pygame    #imports pygame
import time    #imports the timer so I can use the tick function to make game 60fps
start= time.time()
#for every function write this   end= time.time()

import math    #imports maths
import sys    #imports system
import random
from random import *
from time import *    #imports all modules from time
from pygame import *    #imports all pygame files
from pygame.math import *
from pygame.mixer import *
print(start)
win_height = 750    #height of window is 750 pixles
win_width = 1050    #height of window is 1050 pixels
half_win_width = int(win_width / 2)    #will be used to centre camera
half_win_height = int(win_height / 2)

white=(255, 255, 255)
black=(0, 0, 0)
gray=(50, 50, 50)
red=(255, 0, 0)
green=(0, 255, 0)
blue=(0, 0, 255)
yellow=(255, 255, 0)

display = (win_width, win_height)    #creates the window as 500*500 pixels
depth = 32    #prevents infinate recursion
flags = 0    #message to Les: I don't really know what this does, however I have seen it in many places being used, therefore I assumed that it was important
camera_slack = 30    #how many pixels the player can move before the camera moves with them

pygame.init()

mixer.init()
pygame.mixer.music.load('Caravan Palace - Lone Digger [Clip officiel].mp3')    #plays music within my game folder
#pygame.mixer.music.load('Toby Fox - Megalovania [Electro Swing Remix].mp3')    #plays music within my game folder
pygame.mixer.music.play(-1)    #loops music infinately

myfont = pygame.font.SysFont('Comic Sans MS', 30)

def main_menu():
    pygame.init()
    screen = pygame.display.set_mode(display, flags, depth)
    pygame.display.set_caption("Super Castlevania Man")
    timer = pygame.time.Clock()


def main():    #main game function
    global cameraX, cameraY
    pygame.init()
    screen = pygame.display.set_mode(display, flags, depth)
    pygame.display.set_caption("Super Castlevania Man")
    timer = pygame.time.Clock()

    move_cameraX = 0
    move_cameraY = 0

    up = down = left = right = running = False
    background = pygame.Surface((32,32))    #the background takes up space on the screen
    background.convert()
    background.fill(pygame.Color("#000000"))    #background is black
    entities = pygame.sprite.Group()
    player = Player_class(32, 32*15)    #the player is 32*32 pixels large
    platforms = []

    x = y = 0
    blank_level = [
        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "P                               P",
        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"]
    def print_level(level):
        for row in level:
            print(row)

    new_level = blank_level

    #Randomly Generate levels
    #First do the platforms
    #Pick a random number of platforms (6 - 12)
    #For those then pick a row which doesn't have one on (I.e. only has two Ps in), and pick a start cell and a length (3-7) -> ensure it cuts off @ wall
    #Pick a random empty cell for E to go into
    for z in range (0,15):
        plat_len = (randint(1, 7))
        plat_start = (randint(3, 29))
        row = (randint(3, 19))
        new_level[row] = new_level[row][0:plat_start]+("P"*plat_len)+new_level[row][plat_start+plat_len:]

    #Pick a random empty cell for E to go into
    new_level[5] = new_level[5][0:4]+"E"+new_level[5][5:]

    for row in blank_level:
        for col in row:
            if col == "P":
                p = Platform(x, y)    #makes P a solid object
                platforms.append(p)
                entities.add(p)
            if col == "E":
                e = Exit_block(x, y)
                platforms.append(e)
                entities.add(e)
            x += 32
        y += 32
        x = 0

    entities.add(player)
    enemy = Enemy(60, 200, player)    #Spawns enemy
    enemy_list = pygame.sprite.Group()    #creates an enemy group
    enemy_list.add(enemy)    #Add an enemy to the group

    while 1:
        timer.tick(60)    #makes game run at 60 frames per second

        for e in pygame.event.get():    #shortens event to e
            if e.type == QUIT:
                return
            if e.type == KEYDOWN and e.key == K_ESCAPE:
                return
            if e.type == KEYDOWN and e.key == K_UP:
                up = True
                move_cameraY = -10
            if e.type == KEYDOWN and e.key == K_DOWN:
                down = True
                move_cameraY = 10
            if e.type == KEYDOWN and e.key == K_LEFT:
                left = True
                move_cameraX = -10
            if e.type == KEYDOWN and e.key == K_RIGHT:
                right = True
                move_cameraX = 10
            if e.type == KEYDOWN and e.key == K_SPACE:
                running = True

            if e.type == KEYUP and e.key == K_UP:
                up = False
                move_cameraY = 0
            if e.type == KEYUP and e.key == K_DOWN:
                down = False
                move_cameraY = 0
            if e.type == KEYUP and e.key == K_RIGHT:
                right = False
                move_cameraX = 0
            if e.type == KEYUP and e.key == K_LEFT:
                left = False
                move_cameraX = 0
            if e.type == KEYUP and e.key == K_RIGHT:
                right = False        

        # Update the game.
        for e in enemy_list:
            e.update(platforms)
        player.update(up, down, left, right, running, platforms)

        # Draw everything.
        for y in range(32):    #draws the background
            for x in range(32):
                screen.blit(background, (x * 32, y * 32))
        entities.draw(screen)
        enemy_list.draw(screen)
        pygame.display.flip()  # You need only one flip or update call per frame.


class Entity(pygame.sprite.Sprite):    #makes player a sprite
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)    #sets sprite to initiate


class Player_class(Entity):    #defines player class
    def __init__(self, x, y):    #x is the player x coordinate, y is the player y coordinate
        Entity.__init__(self)    #the player is an entity
        self.xvel = 0    #how fast the player is moving left and right
        self.yvel = 0    #how fast the player is moving up and down
        self.onGround = False    #assumes the player is in the air
        self.image = pygame.Surface((32,32))    #the player is 32*32 pixels
        self.image.fill(pygame.Color("#0000FF"))    #makes the player blue
        self.rect = pygame.Rect(x, y, 32, 32)
        self.x = x
        self.y = y

    def update(self, up, down, left, right, running, platforms):
        if up:
            if self.onGround:
                self.yvel -= 10    #only jump if player is on the ground
        if down:
            pass
        if running:
            self.xvel = 12
        if left:
            self.xvel = -8
        if right:
            self.xvel = 8
        if not self.onGround:

            self.yvel += 0.3    #only accelerate with gravity if in the air

            if self.yvel > 100: self.yvel = 100    #terminal velocity = 100
        if not(left or right):
            self.xvel = 0

        self.rect.left += self.xvel    #falls or jumps

        self.collide(self.xvel, 0, platforms)    #creates collisions along the x axis

        self.rect.top += self.yvel    #creates collisions along the y axis

        self.onGround = False;    #assumes that the player is in the air
        # do y-axis collisions
        self.collide(0, self.yvel, platforms)

    def collide(self, xvel, yvel, platforms):
        for p in platforms:
            if pygame.sprite.collide_rect(self, p):
                if isinstance(p, Exit_block):
                    pygame.quit()
                    sys.exit()
                if xvel > 0:
                    self.rect.right = p.rect.left
                if xvel < 0:
                    self.rect.left = p.rect.right
                if yvel > 0:
                    self.rect.bottom = p.rect.top
                    self.onGround = True
                    self.yvel = 0
                if yvel < 0:
                    self.rect.top = p.rect.bottom


class Platform(Entity):
    def __init__(self, x, y):
        Entity.__init__(self)
        self.image = pygame.Surface((32, 32))
        self.image.fill(pygame.Color("#FFFFFF"))
        self.rect = pygame.Rect(x, y, 32, 32)


class Exit_block(Platform):
    def __init__(self, x, y):
        Platform.__init__(self, x, y)
        self.image.fill(pygame.Color("#00FF00"))#exit block is green


class Enemy(Entity):
    def __init__(self, x, y, player):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((32, 32))
        self.xvel = 0
        self.yvel = 0
        self.image.fill(pygame.Color("#FF0000"))    #Enemy is red
        self.rect = pygame.Rect(250, 50, 32, 32)
        #
        #
        #
        #
        """
        if pygame.time.Clock == 20:
            self.rect = pygame.Rect(250, 50, 32, 32)
        """
        self.player = player


    def collide(self, xvel, yvel, platforms):    # Check if the enemy collides with the player.
        if self.rect.colliderect(self.player.rect):
            pygame.quit()
            sys.exit()
        for p in platforms:
            if pygame.sprite.collide_rect(self, p):
                if xvel > 0:
                    self.rect.right = p.rect.left
                if xvel < 0:
                    self.rect.left = p.rect.right
                if yvel > 0:
                    self.rect.bottom = p.rect.top
                if yvel < 0:
                    self.rect.top = p.rect.bottom

    def move(self, xvel, platforms, speed=4):   # chase movement
        for p in platforms:    #if the top of the enemy is touching the bottom of a platform, move the enemy to the right
            if pygame.sprite.collide_rect(self, p):
                if xvel == 15:
                    self.rect.top = p.rect.bottom


        if self.rect.x > self.player.rect.x:    # Movement along x direction 
            self.xvel = -speed
        elif self.rect.x < self.player.rect.x:
            self.xvel = speed
        if self.rect.y < self.player.rect.y:    # Movement along y direction
            self.yvel = speed
        elif self.rect.y > self.player.rect.y:
            self.yvel = -speed




    def update(self, platforms):
        self.move(self, platforms)  # Set the velocity.

        self.rect.left += self.xvel
        self.collide(self.xvel, 0, platforms)    #creates collisions along the x axis

        self.rect.top += self.yvel    #creates collisions along the y axis
        self.collide(0, self.yvel, platforms)


if __name__ == "__main__":
    main()
    pygame.quit()

Solution

  • Define start ahead of the while loop, subtract the current time (now) from the start time to see if the desired time has passed and then set start to now.

    start = pygame.time.get_ticks()
    
    while 1:
        # ... code omitted.
    
        now = pygame.time.get_ticks()
        # When 20000 ms have passed.
        if now - start > 20000:
            start = now
            enemy = Enemy(60, 200, player)
            enemy_list.add(enemy)