In PyGame there are two methods that can and usually are used for this type of tasks:
-
pygame.time.get_ticks
: This method gives us the last milliseconds since pygame.init()
was called.
-
pygame.time.set_timer
: It allows to launch an event repetitively every x milliseconds and that we can capture in the event queue and launch a response when that event is present.
In principle with both methods we can play enough to adapt to a multitude of situations that require timing or schedule certain tasks without blocking of course the mainloop.
To illustrate its use a little we will see two examples:
Sprite changes position every x time repetitively.
An example is the tetrix pieces. For this we can use pygame.time.set_timer
. Of course, the possibilities are not limited to moving the object, we can perform any task repetitively every x milliseconds.
We can make multiple calls to pygame.time.set_timer
, each one will have its own timer and will place the assigned event when it touches the event queue.
To stop a timer for a given event, simply re-call the method by passing 0 in the second argument (milliseconds).
import sys
import random
import pygame
from pygame.locals import *
ANCHO = 400
ALTO = 200
NEGRO = (0, 0, 0)
FPS = 60
class Square(pygame.sprite.Sprite):
def __init__(self):
super(Square, self).__init__()
self.image = pygame.image.load("square.png")
self.rect = self.image.get_rect()
self.rect.centery = ALTO / 2
def move(self):
new_x = self.rect.left + ((ANCHO-self.rect.width)/4)
if new_x > ANCHO:
new_x = 0
self.rect.left = new_x
def game():
pygame.init()
pygame.key.set_repeat(1, 25)
all_sprites = pygame.sprite.Group()
square = Square()
all_sprites.add(square)
ventana = pygame.display.set_mode((ANCHO, ALTO))
pygame.display.set_caption("Game")
fps_clock = pygame.time.Clock()
# Creamos nuestro timer, que lanzará el evento cada segundo (1000 ms)
pygame.time.set_timer(pygame.USEREVENT + 1, 1000)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# comprobamos si el timer ha lanzado el evento
## En caso afirmativo llamamos al método move del sprite.
elif event.type == pygame.USEREVENT + 1:
square.move()
dt = fps_clock.tick(FPS) / 1000.0
all_sprites.update(dt)
ventana.fill(NEGRO)
all_sprites.draw(ventana)
pygame.display.flip()
if __name__ == "__main__":
game()
Make a sprite move to a certain position after two seconds since it was created and after another two seconds it will be destroyed.
This is something similar in principle to what you want, in this case we are going to use pygame.time.get_ticks
. Pressing the space creates a new sprite (limited to 5 simultaneous sprites), when 2 seconds pass since it is created it moves to the center of the screen, after another two seconds it disappears:
import sys
import random
import pygame
from pygame.locals import *
ANCHO = 700
ALTO = 695
NEGRO = (0, 0, 0)
FPS = 60
class Square(pygame.sprite.Sprite):
def __init__(self):
super(Square, self).__init__()
self.image = pygame.image.load("square.png")
self.rect = self.image.get_rect()
self.rect.center=(random.randrange(self.rect.width//2, ANCHO-self.rect.width//2),
random.randrange(self.rect.height//2, ALTO-self.rect.height//2))
self.init_ticks = pygame.time.get_ticks()
def update(self, dt):
# Comprobamos los milisegundos que tiene el sprite de existencia
ticks = pygame.time.get_ticks() - self.init_ticks
# Si han pasado mas de 4 segundos desde que se creo lo destruimos
if ticks >= 4000:
self.kill()
# Si han pasado 2 segundos desde que se creo lo movemos
elif ticks >= 2000:
self.rect.centerx = ANCHO/2
def game():
pygame.init()
pygame.key.set_repeat(1, 25)
all_sprites = pygame.sprite.Group()
squares = pygame.sprite.Group()
ventana = pygame.display.set_mode((ANCHO, ALTO))
pygame.display.set_caption("Game")
fps_clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_SPACE and len(squares) < 5:
square = Square()
squares.add(square)
all_sprites.add(square)
dt = fps_clock.tick(FPS) / 1000.0
all_sprites.update(dt)
ventana.fill(NEGRO)
all_sprites.draw(ventana)
pygame.display.flip()
if __name__ == "__main__":
game()
There are only two simple examples to try to illustrate a general idea, depending on the particular situation we can adapt the code to cover the specific needs.
If someone wants to reproduce the examples, this is the sprite used ( square.png
):