Pygame多线程 [英] Multithreading with Pygame

查看:315
本文介绍了Pygame多线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在编写一个使用线程的简单Pygame应用程序时遇到了麻烦.请记住,这是我编写的第一个多线程代码.

I'm having some trouble writing a simple Pygame application that uses threads. Please keep in mind that this is the first multithreaded code I've ever written.

这是情况.我正在编写一个简单的应用程序,它将在屏幕上绘制一些时髦的线条.我的问题是,在绘制线条时,应用程序无法处理输入,因此(例如)在完成线条之前,我无法关闭窗口.这就是我的原始代码:

Here's the situation. I'm writing a simple app that will draw some funky lines to the screen. My problem is that while I'm drawing the lines, the app can't handle input, so I can't (for example) close the window until the lines are finished. This is what my original code looked like:

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()

如您所见,事件循环仅在绘制完成后才运行,因此在此之前,窗口关闭按钮没有响应.我认为将绘图代码放入自己的线程中可能会有所帮助,因此我将代码更改为:

As you can see, the event loop is only run when the drawing is done, so until then the window close button is unresponsive. I thought that putting the drawing code into its own thread might help, so I changed the code to this:

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()

但是我得到的只是一个黑屏,它也不响应输入.我在这里做什么错了?

But all I get is a black screen which doesn't respond to input either. What am I doing wrong here?

推荐答案

尽管我从未使用过pygame,但我怀疑您是否可以(或应该)从不同的线程调用其API.您的所有绘制都应在主事件循环中完成.

Although I have never used pygame, I doubt that you can (or should) call its API from different threads. All your drawing should be done in the main event loop.

我想您必须改变游戏开发的思维方式.不用使用time.sleep()暂停图形,而是创建一个可以定期更新的对象.通常,这要分两步完成-update()可以在时间上推进对象状态,而draw()可以呈现对象的当前状态.在主循环的每次迭代中,将更新所有对象,然后绘制所有对象.请注意,draw()应该假定屏幕为空白,并绘制到当前时间为止所需的每一行.

I guess you have to change the way you are thinking for game development. Instead of using time.sleep() to pause the drawing, create an object that can be updated in regular intervals. Typically, this is done in two passes -- update() to advance the object state in time, and draw() to render the current state of the object. In every iteration of your main loop, all objects are updated, then all are drawn. Note that draw() should assume that the screen is blank and draw every line that is needed up to the current time.

在您的简单情况下,您可以摆脱一些简单的事情.将draw()函数中的time.sleep()替换为yield.这样,您将获得一个迭代器,该迭代器将产生建议的时间,等待下一次迭代.在主循环之前,通过调用draw()创建一个迭代器,并初始化下次绘制的时间:

In your simple case, you could get away with something simpler. Replace the time.sleep() in your draw() function with yield. This way you get an iterator that will yield the recommended amount of time to wait until the next iteration. Before the main loop, create an iterator by calling draw() and initialize the time when the next draw should occur:

draw_iterator = draw()
next_draw_time = 0  # Draw immediately

然后,在主循环中,在处理用户输入后,检查是否该绘制:

Then, in the main loop, after handling user input, check if it's time to draw:

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

如果是这样,请运行下一个迭代并安排下一个绘制时间:

If so, run the next iteration and schedule the next draw time:

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

这篇关于Pygame多线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆