Multihilo con Pygame

Tengo algunos problemas para escribir una aplicación Pygame simple que usa hilos. Tenga en cuenta que este es el primer código multiproceso que he escrito.

Aquí está la situación. Estoy escribiendo una aplicación simple que dibujará algunas líneas funky en la pantalla. Mi problema es que mientras estoy dibujando las líneas, la aplicación no puede manejar la entrada, por lo que no puedo (por ejemplo) cerrar la ventana hasta que las líneas terminen. Así es como se veía mi código original:

import time import pygame from pygame.locals import * SIZE = 800 def main(): screen = pygame.display.set_mode((SIZE, SIZE)) for interval in xrange(50, 1, -5): screen.fill((0, 0, 0)) for i in xrange(0, SIZE, interval): pygame.draw.aaline(screen, (255, 255, 255), (i+interval, 0), (0, SIZE-i)) pygame.draw.aaline(screen, (255, 255, 255), (i, 0), (SIZE, i+interval)) pygame.draw.aaline(screen, (255, 255, 255), (SIZE, i), (SIZE-i-interval, SIZE)) pygame.draw.aaline(screen, (255, 255, 255), (SIZE-i, SIZE), (0, SIZE-i-interval)) pygame.display.update() time.sleep(0.03) time.sleep(3) while True: for evt in pygame.event.get(): if evt.type == QUIT: return if __name__ == '__main__': pygame.init() main() pygame.quit() 

Como puede ver, el bucle de eventos solo se ejecuta cuando se realiza el dibujo, por lo tanto, hasta entonces, el botón de cierre de la ventana no responde. Pensé que poner el código de dibujo en su propio hilo podría ayudar, así que cambié el código a esto:

 import threading, time import pygame from pygame.locals import * SIZE = 800 def draw(): screen = pygame.display.set_mode((SIZE, SIZE)) for interval in xrange(50, 1, -5): screen.fill((0, 0, 0)) for i in xrange(0, SIZE, interval): pygame.draw.aaline(screen, (255, 255, 255), (i+interval, 0), (0, SIZE-i)) pygame.draw.aaline(screen, (255, 255, 255), (i, 0), (SIZE, i+interval)) pygame.draw.aaline(screen, (255, 255, 255), (SIZE, i), (SIZE-i-interval, SIZE)) pygame.draw.aaline(screen, (255, 255, 255), (SIZE-i, SIZE), (0, SIZE-i-interval)) pygame.display.update() time.sleep(0.03) time.sleep(3) def main(): threading.Thread(target=draw).start() while True: for evt in pygame.event.get(): if evt.type == QUIT: return if __name__ == '__main__': pygame.init() main() pygame.quit() 

Pero todo lo que consigo es una pantalla negra que tampoco responde a la entrada. ¿Qué estoy haciendo mal aquí?

Aunque nunca he usado pygame, dudo que puedas (o debas) llamar a su API desde diferentes hilos. Todo su dibujo debe hacerse en el bucle principal del evento.

Supongo que tienes que cambiar la forma en que piensas para el desarrollo de juegos. En lugar de usar time.sleep() para pausar el dibujo, cree un objeto que se pueda actualizar en intervalos regulares. Por lo general, esto se hace en dos pases: update() para avanzar el estado del objeto en el tiempo y draw() para representar el estado actual del objeto. En cada iteración de su bucle principal, todos los objetos se actualizan, luego todos se dibujan. Tenga en cuenta que draw() debe asumir que la pantalla está en blanco y dibuje cada línea que se necesite hasta la hora actual.

En tu caso simple, podrías salirte con algo más simple. Reemplace el time.sleep() en su función draw() con yield . De esta manera, obtendrá un iterador que le dará la cantidad de tiempo recomendada para esperar hasta la siguiente iteración. Antes del bucle principal, cree un iterador llamando a draw() e inicialice la hora en que debería ocurrir el siguiente sorteo:

 draw_iterator = draw() next_draw_time = 0 # Draw immediately 

Luego, en el bucle principal, después de manejar la entrada del usuario, verifique si es el momento de dibujar:

 current_time = time.time() if current_time >= next_draw_time: 

Si es así, ejecute la siguiente iteración y programe la próxima hora de sorteo:

  try: timeout = next(draw_iterator) except StopIteration: # The drawing is finished, exit the main loop? break next_draw_time = current_time + timeout