一段时间后,pyglet windows 与 schedule_once 挂起

pyglet windows hang with schedule_once after some time

对于上下文,我正在尝试将 OpenAI gym 与我编写的 pyglet 俄罗斯方块游戏一起使用。我面临的问题归结为下面的 MWE。

经过始终相同的时间后,此处为约 9 秒,window 冻结,但来自 toto 函数和渲染函数的打印仍在打印。 我快要疯了。 Pyglet 看起来不错,但我几乎找不到任何文档,而官方文档几乎没有帮助。 如果我用带有 on_draw() 函数的更简单的代码做同样的事情,没问题,但我需要这个用于健身房部分。

谢谢

import pyglet
import time

class Display(pyglet.window.Window):
    def __init__(self, ww, wh):
        super().__init__(width=ww, height=wh)

class Env:
    def __init__(self):
        self.window = Display(640, 480)

    def render(self, i):
        self.window.clear()
        label = pyglet.text.Label('iter {:f}'.format(i),
                                  font_size=16,
                                  x=300,
                                  y=200,
                                  anchor_x='left', anchor_y='center')
        label.draw()
        print('iter {:f}'.format(i))
        self.window.flip()

env = Env()

def toto(dt):
    for t in range(300):
        time.sleep(0.5)
        print("toto {:d}".format(t))
        env.render(t)
    print("done")
pyglet.clock.schedule_once(toto, 1)
pyglet.app.run()

至少在 Windows 上,我无法完全重现您遇到的问题,但我确实注意到 window 在移动、单击时冻结,minimized/restored.问题似乎是您不发送此类事件,因此它们将其放在事件队列中并阻止进一步绘制。快速修复是在调用 self.window.clear().

之后调用 self.window.dispatch_events
import pyglet
import time

class Display(pyglet.window.Window):
    def __init__(self, ww, wh):
        super().__init__(width=ww, height=wh)

class Env:
    def __init__(self):
        self.window = Display(640, 480)

    def render(self, i):
        self.window.clear()
        self.window.dispatch_events()
        label = pyglet.text.Label('iter {:f}'.format(i),
                                  font_size=16,
                                  x=300,
                                  y=200,
                                  anchor_x='left', anchor_y='center')
        label.draw()
        print('iter {:f}'.format(i))
        self.window.flip()

env = Env()

def toto(dt):
    for t in range(300):
        time.sleep(0.5)
        print("toto {:d}".format(t))
        env.render(t)
    print("done")
pyglet.clock.schedule_once(toto, 1)
pyglet.app.run()

您在这里似乎没有充分利用默认的 Pyglet 事件循环,因此您可能只想编写自己的事件循环。这是您可以做到这一点的一种方法。

import pyglet
import time

class Display(pyglet.window.Window):
    def __init__(self, ww, wh):
        super().__init__(width=ww, height=wh)
        self.label = pyglet.text.Label('',
                                  font_size=16,
                                  x=300,
                                  y=200,
                                  anchor_x='left', anchor_y='center')
        
    def on_draw(self):
        self.clear()
        self.label.draw()

class Env:
    def __init__(self):
        self.window = Display(640, 480)

    def render(self, i):
        self.window.label.text = "iter {:f}".format(i)
        self.window.switch_to()
        self.window.dispatch_events()
        self.window.dispatch_event('on_draw')
        print('iter {:f}'.format(i))
        self.window.flip()

env = Env()

def toto():
    for t in range(300):
        time.sleep(0.5)
        print("toto {:d}".format(t))
        env.render(t)
    print("done")

toto()