I’m trying to work on a simple Pygame program for a project that simply displays some faces and talks in a text to speech voice, but there is a while loop at the end that is necessary for the code to run but blocks another while loop that I need for the program from running. The while loop I’m trying to add uses time.sleep()
, so if I try to put it into the same block as the first one which needs to be constantly running the program crashes. I’m sure I’m probably looking over something obvious but any help would be appreciated, thanks!
Here’s the code:
from random import randint from time import sleep import pygame import pygame.freetype import time import random run = True pygame.init() #faces face = ['^-^', '^v^', '◠◡◠', "'v'", '⁀◡⁀'] talkingFace = ['^o^', '^▽^', '◠▽◠', "'▽'", '⁀ᗢ⁀'] currentFace = random.choice(face) #background screen = pygame.display.set_mode((800,600)) screen.fill((0,0,0)) #font and size myFont = pygame.font.Font('unifont.ttf', 100) #face render faceDisplay = myFont.render(str(currentFace), 1, (0,255,0)) #center and draw face text_rect = faceDisplay.get_rect(center=(800/2, 600/2)) screen.blit(faceDisplay, text_rect) #prevent crashes while run: for e in pygame.event.get(): if e.type == pygame.QUIT: run = False pygame.display.flip() #loop i'm trying to add while run: faceDisplay = myFont.render(str(currentFace), 1, (0,255,0)) screen.blit(faceDisplay, text_rect) time.sleep(randint(5, 10))
Advertisement
Answer
No, that’s not the way it goes. You have an application loop so use it. time.sleep
, pygame.time.wait()
or pygame.time.delay
is not the way to wait or delay something in a typical application. The game does not respond while you wait. Use pygame.time.get_ticks()
to measure the 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.
Calculate the point in time when the text needs to be changed. Get a new random text and render the text Surface after the current time is greater than the calculated point of time. Calculate a new random point in time which is greater than the current time:
next_render_time = 0 while run: current_time = pygame.time.get_ticks() # [...] if current_time >= next_render_time: currentFace = random.choice(face) faceDisplay = myFont.render(str(currentFace), 1, (0,255,0)) next_render_time = current_time + randint(5, 10) * 1000 screen.fill((0,0,0)) screen.blit(faceDisplay, text_rect) pygame.display.flip()
The time is multiplied by 1000 (randint(5, 10) * 1000
), since the time unit of pygame.time.get_ticks()
is milliseconds.
Actually, you can also use a timer event. See How do I use a PyGame timer event?.
In your case, however, the time interval is not constant. It’s a bit odd to use a timer event on a dynamically changing interval. I would prefer to use a timer event for an action that needs to be performed at constant intervals. But that’s just my opinion.
Complete example:
from random import randint from time import sleep import pygame import pygame.freetype import time import random run = True pygame.init() #faces face = ['^-^', '^v^', '◠◡◠', "'v'", '⁀◡⁀'] talkingFace = ['^o^', '^▽^', '◠▽◠', "'▽'", '⁀ᗢ⁀'] currentFace = random.choice(face) #background screen = pygame.display.set_mode((800,600)) #font and size myFont = pygame.font.Font('unifont.ttf', 100) #face render faceDisplay = myFont.render(str(currentFace), 1, (0,255,0)) #center and draw face text_rect = faceDisplay.get_rect(center=(800/2, 600/2)) next_render_time = 0 #prevent crashes while run: current_time = pygame.time.get_ticks() for e in pygame.event.get(): if e.type == pygame.QUIT: run = False if current_time >= next_render_time: currentFace = random.choice(face) faceDisplay = myFont.render(str(currentFace), 1, (0,255,0)) next_render_time = current_time + randint(5, 10) * 1000 screen.fill((0,0,0)) screen.blit(faceDisplay, text_rect) pygame.display.flip()