How Can One Continuously Generate and Track Several Random Objects with a Time Delay in Pygame

Pygame - drop enemies randomly in time

I recommend to use a timer event. Use pygame.time.set_timer() to repeatedly create an USEREVENT. e.g.:

milliseconds_delay = 3000
enemy_spawn_event = pygame.USEREVENT + 1
pygame.time.set_timer(enemy_spawn_event, milliseconds_delay)

Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to start at pygame.USEREVENT. In this case pygame.USEREVENT+1 is the event id for the timer event, which spawns the enemies.

Create a new enemy when the event occurs in the event loop:

milliseconds_delay = 3000
enemy_spawn_event = pygame.USEREVENT + 1
pygame.time.set_timer(enemy_spawn_event, milliseconds_delay)

while not game_over:

# [...]

# Scoring and lifepoints systems
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()

if event.type == enemy_spawn_event and len(all_enemies) < number_of_enemies:
all_enemies.append(Enemies(int(SCREEN_WIDTH/2), 0, color = YELLOW, position = "top"))
for e in all_enemies:
e.randomise()
time_counter = 0

Pygame : Repeating an action every x amount of time

I recommend to use a timer event. Use pygame.time.set_timer() to repeatedly create an USEREVENT. e.g.:

banana_delay = 500 # 0.5 seconds
banana_event = pygame.USEREVENT + 1
pygame.time.set_timer(banana_event, banana_delay)

Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to be between pygame.USEREVENT (24) and pygame.NUMEVENTS (32). In this case pygame.USEREVENT+1 is the event id for the timer event, which spawns the bullets.

Create a new banana when the event occurs in the event loop:

def check_events(screen, settings, bananas, monkey):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# [...]

if event.type == banana_event:
create_banana(screen, settings, bananas)

The timer event can be stopped by passing 0 to the time parameter.


If you want spawn the bananas by a random time spawn, then you have to change the timespan (in milliseconds) randomly. Use random.randint(a, b) to generate random times:

if event.type == banana_event:
create_banana(screen, settings, bananas)
banana_delay = random.randint(500, 3000) # random from 0.5 to 3 seconds
pygame.time.set_timer(banana_event, banana_delay)

How can I use time to make random arrows in pygame?

First of all don't create on class for each arrow. A class is an object with attributes. Use the attributes of a class and create instances of the class with different appearance and behavior. Add parameters to the signature of the constructor and use the the parameters to the initialize the attributes.

Add parameters for the position and image filename:

class ArrowGray(pygame.sprite.Sprite):

def __init__(self, pos, imagename):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(imagename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.center = pos

class Arrow(pygame.sprite.Sprite):

def __init__(self, pos, imagename):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(imagename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.center = pos

def update(self):
self.rect.x += 5
if (self.rect.left > (WIDTH + 50)):
self.rect.right = 0

a1g = ArrowGray((750, 25), "gray right.png")
a2g = ArrowGray((750, 125), "gray left.png")
a3g = ArrowGray((750, 250), "gray up.png")
a4g = ArrowGray((750, 375), "gray down.png")

a1 = Arrow((25, 25), "red right.png")
a2 = Arrow((25, 125), "blue left.png")
a3 = Arrow((25, 250), "green up.png")
a4 = Arrow((25, 375), "yellow down.png")

I recommend to use a timer event. Use pygame.time.set_timer() to repeatedly create an USEREVENT. e.g.:

arrowGrayList = [a1g, a2g, a3g, a4g]
arrowList = [a1, a2, a3, a4]
allArrows = pygame.sprite.Group()

millisecondsDelay = 500 # 0.5 seconds
arrowTimerEvent = pygame.USEREVENT + 1
pygame.time.set_timer(arrowTimerEvent, millisecondsDelay)
spawned = 0

while running:
clock.tick(FPS)

#Update
allArrows.update()

for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False

if event.type == arrowTimerEvent:
if spawned < len(arrowList):
allArrows.add(arrowGrayList[spawned])
allArrows.add(arrowList[spawned])
spawned += 1

keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
if pygame.sprite.collide_rect(a1, a1g):
a1.rect.center = (900, 600)
if keys[pygame.K_LEFT]:
if pygame.sprite.collide_rect(a2, a2g):
a2.rect.center = (900, 600)
if keys[pygame.K_UP]:
if pygame.sprite.collide_rect(a3, a3g):
a3.rect.center = (900, 600)
if keys[pygame.K_DOWN]:
if pygame.sprite.collide_rect(a4, a4g):
a4.rect.center = (900, 600)
#draw
screen.fill(SALMON)
allArrows.draw(screen)

pygame.display.flip()

pygame.quit()

Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to start at pygame.USEREVENT. In this case pygame.USEREVENT+1 is the event id for the timer event, which spawns the arrows.

Spawning multiple instances of the same object concurrently in python

It does not work that way. time.sleep, pygame.time.wait() or pygame.time.delay is not the right way to control time and gameplay within an application loop. The game does not respond while you wait. The application loop runs continuously. You have to measure the time in the loop and spawn the objects according to the elapsed time.

pygame.Surface.fill clears the entire screen. Add the newly created objects to a list. Redraw all of the objects and the entire scene in each frame.

See also Time, timer event and clock


You have 2 options. Use pygame.time.get_ticks() to measure the time. Define a time interval after which a new object should appear. Create an object when the point in time is reached and calculate the point in time for the next object:

object_list = []
time_interval = 500 # 500 milliseconds == 0.1 seconds
next_object_time = 0

while run:
# [...]

current_time = pygame.time.get_ticks()
if current_time > next_object_time:
next_object_time += time_interval
object_list.append(Object())

Minimal example:

Sample Image repl.it/@Rabbid76/PyGame-TimerSpawnObjects

Sample Image

import pygame, random
pygame.init()
window = pygame.display.set_mode((300, 300))

class Object:
def __init__(self):
self.radius = 50
self.x = random.randrange(self.radius, window.get_width()-self.radius)
self.y = random.randrange(self.radius, window.get_height()-self.radius)
self.color = pygame.Color(0)
self.color.hsla = (random.randrange(0, 360), 100, 50, 100)

object_list = []
time_interval = 200 # 200 milliseconds == 0.2 seconds
next_object_time = 0

run = True
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False

current_time = pygame.time.get_ticks()
if current_time > next_object_time:
next_object_time += time_interval
object_list.append(Object())

window.fill(0)
for object in object_list[:]:
pygame.draw.circle(window, object.color, (object.x, object.y), round(object.radius))
object.radius -= 0.2
if object.radius < 1:
object_list.remove(object)
pygame.display.flip()

pygame.quit()
exit()

The other option is to use the pygame.event module. Use pygame.time.set_timer() to repeatedly create a USEREVENT in the event queue. The time has to be set in milliseconds. e.g.:

object_list = []
time_interval = 500 # 500 milliseconds == 0.1 seconds
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, time_interval)

Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to be between pygame.USEREVENT (24) and pygame.NUMEVENTS (32). In this case pygame.USEREVENT+1 is the event id for the timer event.

Receive the event in the event loop:

while run:
for event in pygame.event.get():
if event.type == timer_event:
object_list.append(Object())

The timer event can be stopped by passing 0 to the time argument of pygame.time.set_timer.

Minimal example:

Sample Image repl.it/@Rabbid76/PyGame-TimerEventSpawn

Sample Image

import pygame, random
pygame.init()
window = pygame.display.set_mode((300, 300))

class Object:
def __init__(self):
self.radius = 50
self.x = random.randrange(self.radius, window.get_width()-self.radius)
self.y = random.randrange(self.radius, window.get_height()-self.radius)
self.color = pygame.Color(0)
self.color.hsla = (random.randrange(0, 360), 100, 50, 100)

object_list = []
time_interval = 200 # 200 milliseconds == 0.2 seconds
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, time_interval)

run = True
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == timer_event:
object_list.append(Object())

window.fill(0)
for object in object_list[:]:
pygame.draw.circle(window, object.color, (object.x, object.y), round(object.radius))
object.radius -= 0.2
if object.radius < 1:
object_list.remove(object)
pygame.display.flip()

pygame.quit()
exit()

Trying to delay a specific function for spawning enemy after a certain amount of time

In pygame exists a timer event. Use pygame.time.set_timer() to repeatedly create a USEREVENT in the event queue.. The time has to be set in milliseconds:

pygame.time.set_timer(pygame.USEREVENT, 1000) # 1 second

Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to be between pygame.USEREVENT (24) and pygame.NUMEVENTS (32). In this case the value of pygame.USEREVENT is the event id for the timer event.

Receive the event in the event loop:

running = True
while run:

for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False

elif event.type == pygame.USEREVENT:
# [...]

The timer event can be stopped by passing 0 to the time argument of pygame.time.set_timer.

See also Spawning multiple instances of the same object concurrently in python.


Create a list of moles and add a random position to the list in mole_spawn_easy:

moles = []

def mole_spawn_easy():
molex = random.randint(50, 950)
moley = random.randint(450, 682)
moles.append((molex, moley))

Draw the moles in the main application loop:

while run:
# [...]

for pos in moles:
screen.blit(mole, pos)

See the example:

moles = []

def mole_spawn_easy():
molex = random.randint(50, 950)
moley = random.randint(450, 682)
moles.append((molex, moley))

pygame.time.set_timer(pygame.USEREVENT, 1000)

while run:

ax, ay = pygame.mouse.get_pos()

for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False

if event.type == pygame.USEREVENT:
counter -= 1
text = ("Time Left: " + str(counter)).rjust(3)
if counter > 0:
mole_spawn_easy()
else:
print("game over")

screen.blit(background, [0,0])

for pos in moles:
screen.blit(mole, pos)
screen.blit(aim, ((ax - 32 ),(ay - 32)))
screen.blit(font.render(text, True, (0, 0, 0)), (32, 48))

pygame.display.flip()
clock.tick(FPS)

Time Delay and keeping track of the of # of click

Never use a delay in your application loop. Use the application loop. Compute the point in time when the rectangles have to change color back. Change the color after the current time is greater than the calculated point of time.

In pygame the system time can be obtained by calling pygame.time.get_ticks(), which returns the number of milliseconds since pygame.init() was called. See pygame.time module.

Add 2 attributes self.tile_clicked = 0 and self.turn_white_time = 0 to the class Game:

class Game:

def __init__(self,surface,surface_width,surface_height):
# [...]

self.tile_clicked = []
self.turn_white_time = 0

Compute the the point in time when the rectangles have to change color back after the 2nd rectangle was clicked:

class Game:
# [...]

def handle_color_change(self, event):

if len(self.tile_clicked) < 2:

if 1 not in self.tile_clicked:
if event.button == 1 and self.tile_left.inside_tile(event.pos) == True:
self.tile_left.set_color(random.choice(self.color_options))
self.tile_clicked.append(1)

if 2 not in self.tile_clicked:
if event.button == 1 and self.tile_right.inside_tile(event.pos) == True:
self.tile_right.set_color(random.choice(self.color_options))
self.tile_clicked.append(2)

if len(self.tile_clicked) == 2:
delay_time = 1000 # 1000 milliseconds == 1 second
self.turn_white_time = pygame.time.get_ticks() + delay_time

get_ticks() returns the current time. A time is just a number. get_ticks() + delay_time is a time in the future. When the program is running, the current time is continuously retrieved and compared with turn_white_time. At some point the current time is greater than turn_white_time and the color of the rectangles is changed.

Change back to the white color after the current time is greater than the calculated point of time in update:

class Game:
# [...]

def update(self):
current_time = pygame.time.get_ticks()
if len(self.tile_clicked) == 2 and current_time > self.turn_white_time:
self.tile_left.set_color(self.default_color)
self.tile_right.set_color(self.default_color)
self.tile_clicked = []

Complete example:

Sample Image

import pygame,time,random
# User-defined functions

def main():
# for initializing all pygame modules
pygame.init()
# this creates the pygame display window
surface_width = 500
surface_height = 400
surface = pygame.display.set_mode((surface_width,surface_height))
# this sets the caption of the window to 'Pong'
pygame.display.set_caption('Painting')

# creates a game object
game = Game(surface, surface_width, surface_height)
# this starts the game loop by calling the play method found in the game object
game.play()
# quits pygame and cleans up the pygame window
pygame.quit()

# User-defined classes

class Game:
# an object in this class represents the complete game

def __init__(self,surface,surface_width,surface_height):
# # Initialize a Game.
# - self is the Game to initialize
# - surface is the display window surface object
# - surface_width is the display width size
# - surface_height is the display height size

# attributes that are needed to run any game
self.surface = surface
self.surface_width = surface_width
self.surface_height = surface_height
self.close_clicked = False
self.surface_color = pygame.Color('black')

# attributes that are needed to run this specific game
self.FPS = 60
self.game_clock = pygame.time.Clock()
self._continue = True
self.score = [0,0]
self.max_mismatch = 5

# Game specific objects
self.default_color = 'white'
self.color_options = ('blue' , 'red', 'yellow', 'green')
self.tile_width = 50
self.tile_height = 150
self.tile_left = Tile( self.default_color, (self.surface_width/3) - self.tile_width, (self.surface_height/2)/ 2 , self.tile_width, self.tile_height , self.surface)
self.tile_right = Tile(self.default_color, self.surface_width/2 + self.tile_width, (self.surface_height/2)/ 2
,self.tile_width, self.tile_height , self.surface)

self.tile_clicked = []
self.turn_white_time = 0



def play(self):
# this is main game loop
# plays the game until the players has closed the window or the score of a players equals the max score
# - self is the game that should be continued or not

while not self.close_clicked:
self.main_handle_events()
self.draw()
self.update()
self.game_clock.tick(self.FPS)


def draw(self):
# this draws the circle and the rectangles that are needed for this specific game
# -self is the Game to draw

self.surface.fill(self.surface_color)
self.tile_left.draw()
self.tile_right.draw()
self.display_score_match()
self.display_score_mismatch(self.surface_width)
pygame.display.update() # makes the updated surface appear on the display



def update(self):
current_time = pygame.time.get_ticks()
if len(self.tile_clicked) == 2 and current_time > self.turn_white_time:
self.tile_left.set_color(self.default_color)
self.tile_right.set_color(self.default_color)
self.tile_clicked = []



def main_handle_events(self):
# handles each user events by changing the game state appropriately
# -self is the Game of whose events are handled

events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
if event.type == pygame.MOUSEBUTTONDOWN:
self.handle_color_change(event)
#self.update_score()
#self.handle_color_change(event)

def display_score_match(self):
text_string = 'Match: ' + str(self.score[0])
text_colour = pygame.Color('white')
text_font = pygame.font.SysFont('Times New Roman',25)
text_image = text_font.render(text_string, True, text_colour)
text_pos = [0,0]
self.surface.blit(text_image, text_pos)

def display_score_mismatch(self, surface_width):
text_string = 'Mismatch: ' + str(self.score[1])
text_colour = pygame.Color('white')
text_font = pygame.font.SysFont('Times New Roman',25)
text_image = text_font.render(text_string, True, text_colour)
text_pos = [(surface_width - text_image.get_width()), 0]
self.surface.blit(text_image, text_pos)



def handle_color_change(self, event):

if len(self.tile_clicked) < 2:

if 1 not in self.tile_clicked:
if event.button == 1 and self.tile_left.inside_tile(event.pos) == True:
self.tile_left.set_color(random.choice(self.color_options))
self.tile_clicked.append(1)

if 2 not in self.tile_clicked:
if event.button == 1 and self.tile_right.inside_tile(event.pos) == True:
self.tile_right.set_color(random.choice(self.color_options))
self.tile_clicked.append(2)

if len(self.tile_clicked) == 2:
delay_time = 1000 # 1000 milliseconds == 1 second
self.turn_white_time = pygame.time.get_ticks() + delay_time


def update_score(self):
if self.tile_left.color_match(self.tile_right) == True:
self.score[0] = self.score[0] + 1
else:
self.score[1] = self.score[1] + 1


class Tile:

def __init__(self, rect_color, rect_left, rect_top, rect_width, rect_height,surface):
# Initialize a rectabgle which is used as a paintbrush.
# - self is the rectangle to initialize
# - rect_color is the pygame.Color of the dot
# - rect_height is the int length of the rectangle in the y axis
# - rect_width is the int width of the rectangle in the x axis
# - rect_left is the int coordinate position of the rectangle in the x axis
# - rect_top is the int coordinate position of the rectangle in the y axis
# - rect_velocity is a list of x and y components and the speed of which the rectangles can move

self.rect_colour = pygame.Color(rect_color)
self.rect_height = rect_height
self.rect_width = rect_width
self.rect_left = rect_left
self.rect_top = rect_top
self.surface = surface
self.rect_parameters = pygame.Rect(rect_left, rect_top, rect_width, rect_height)

def draw(self):
# draws the rectangle on the surface
# - self is the rectangle

pygame.draw.rect(self.surface, self.rect_colour, self.rect_parameters)


def inside_tile(self, position):
inside = False
if self.rect_parameters.collidepoint(position):
inside = True
return inside

def set_color(self, color):
self.rect_colour = pygame.Color(color)

def color_match(self, other_tile):
match = False
if self.rect_colour == other_tile.rect_colour:
match = True
return match

main()

how to spawn a sprite after a time limit and how to display a timer pygame

There are several ways to implement a timer in pygame. You can use the time that pygame.Clock.tick returns to increase or decrease a timer variable, calculate the time difference with pygame.time.get_ticks or use a custom event in conjunction with pygame.time.set_timer.

Example 1 - delta time:

import sys
import random
import pygame as pg

class Block(pg.sprite.Sprite):

def __init__(self, pos):
super().__init__()
self.image = pg.Surface((40, 40))
self.image.fill(pg.Color('sienna1'))
self.rect = self.image.get_rect(topleft=pos)

def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
font = pg.font.Font(None, 30)
all_sprites = pg.sprite.Group()
# Delta time is the time that has passed since clock.tick
# was called the last time.
dt = 0
# We'll subtract dt (delta time) from this timer variable.
timer = 1 # 1 means one second.

done = False

while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True

# Decrease timer to get a countdown.
timer -= dt
# When the timer is below or equal to 0, we spawn
# a new block.
if timer <= 0:
all_sprites.add(Block((random.randrange(600),
random.randrange(440))))
# Reset the countdown timer to one second.
timer = 1
all_sprites.update()
screen.fill(pg.Color('gray15'))
all_sprites.draw(screen)
timer_surface = font.render(
str(round(timer, 3)), True, pg.Color('yellow'))
screen.blit(timer_surface, (20, 20))

pg.display.flip()
# dt = time in seconds that passed since last tick.
# Divide by 1000 to convert milliseconds to seconds.
dt = clock.tick(30) / 1000

if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()

If you want to spawn exactly 1 sprite, you can add another variable like boss_spawned = False and change the timer only if the boss hasn't spawned:

if not boss_spawned:
timer -= dt
if timer <= 0:
all_sprites.add(Block((random.randrange(600),
random.randrange(440))))
boss_spawned = True

Or set the timer to exactly 0 after the spawn and only decrease the timer if it's != 0.

if timer != 0:
timer -= dt
if timer <= 0:
all_sprites.add(Block((random.randrange(600),
random.randrange(440))))
timer = 0

Example 2 - pygame.time.get_ticks (replace the main function above):

def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
font = pg.font.Font(None, 30)
all_sprites = pg.sprite.Group()
# Start time.
now = pg.time.get_ticks()
done = False

while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True

# If the time difference is greater than 1000
# milliseconds, spawn a block.
time_difference = pg.time.get_ticks() - now
if time_difference >= 1000:
all_sprites.add(Block((random.randrange(600),
random.randrange(440))))
# Reset the start time.
now = pg.time.get_ticks()
all_sprites.update()
screen.fill(pg.Color('gray15'))
all_sprites.draw(screen)
timer_surface = font.render(
str(time_difference/1000), True, pg.Color('yellow'))
screen.blit(timer_surface, (20, 20))

pg.display.flip()
clock.tick(30)

If you just want to count the kills or spawned mobs, you can increment a counter variable and then spawn the enemy boss when it exceeds some limit. The following example just counts the mouse clicks and spawns a block after 3 clicks.

def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
font = pg.font.Font(None, 30)
all_sprites = pg.sprite.Group()
# We'll just count mouse clicks in this example.
# You can replace it with the kill count in your game.
clicks = 0
done = False

while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEBUTTONDOWN:
clicks += 1

if clicks >= 3:
all_sprites.add(Block((random.randrange(600),
random.randrange(440))))
clicks = 0
all_sprites.update()
screen.fill(pg.Color('gray15'))
all_sprites.draw(screen)
clicks_surface = font.render(str(clicks), True, pg.Color('yellow'))
screen.blit(clicks_surface, (20, 20))

pg.display.flip()
clock.tick(30)


Related Topics



Leave a reply



Submit