如何在类中使用pyglet

5 投票
3 回答
3608 浏览
提问于 2025-04-18 12:32

在我看到的所有关于Pyglet的教程中,似乎没有一个使用类来包含pyglet.window.Window实例。比如,大多数教程的内容大致是这样的:

import pyglet

game_window = pyglet.window.Window()

@game_window.event
def on_draw():
    #dostuff

while __name__ == "__main__":
    pyglet.app.run()

我在把这段代码重构成一个类时遇到了困难。我的代码是这样的:

import pyglet
from pyglet.gl import *
from Board import Board

class Frontend:
    def __init__(self,xs, ys):
        self.GameInstance = Board(xs,ys)
        self.GameWindow = pyglet.window.Window(width=512, height=512,visible=False)

    @GameWindow.event
    def on_draw(self):
        self.GameWindow.clear()

f = Frontend()

当我运行这段代码时,出现了以下错误:

Traceback (most recent call last):
  File "C:/Users/PycharmProjects/Nothing/2048/Frontend.py", line 7, in <module>
    class Frontend:
  File "C:/Users/PycharmProjects/Nothing/2048/Frontend.py", line 13, in Frontend
    @GameWindow.event
NameError: name 'GameWindow' is not defined

当我试图用 @self.GameWindow.event 替换 @GameWindow.event 来解决NameError时,我得到了:

Traceback (most recent call last):
    File "C:/Users/PycharmProjects/Nothing/2048/Frontend.py", line 7, in <module>
    class Frontend:
    File "C:/Users/PycharmProjects/Nothing/2048/Frontend.py", line 13, in Frontend
    @self.GameWindow.event
NameError: name 'self' is not defined

这是我预期的结果。然而,我不太明白为什么这段代码不工作——有人能解释一下原因以及如何修复它吗?

3 个回答

-3

我猜你需要这样做:

@self.Gamewindow.event
3

正如我在ragezor的回答中提到的,pyglet的文档建议使用继承。

不过,另一个选择是把事件处理的逻辑放在一个单独的类里,叫做EventDispatcher。你可以在这里找到相关信息:http://pyglet.org/doc-current/programming_guide/events.html#creating-your-own-event-dispatcher

就我个人而言,如果我知道只会有一个Frontend实例,我会怀疑是否真的需要一个类。但这又是另一个复杂的问题。至少我想给你提供一个不错的选择,继承Window是不会错的,特别是当你所有的事件都和Window有关的时候。

还有一个第三个想法(算是第四个,因为ragezor给了你两个选择):

class Frontend:

def __init__(self,xs, ys):
    self.GameInstance = Board(xs,ys)
    self.GameWindow = pyglet.window.Window(width=512, height=512,visible=False)

    self.on_draw = self.GameWindow.event(self.on_draw)

def on_draw(self):
    self.GameWindow.clear()

换句话说,就是手动应用@GameWindow.event这个装饰器。

最后一点,不要用驼峰命名法来命名属性,这违反了PEP8的规范,编辑代码的时候让我困惑了一下。可以用game_window来命名。

6

你可以通过继承Window类来实现。这应该是可行的:

class Frontend(pyglet.window.Window):
    def __init__(self, xs, ys):
        self.GameInstance = Board(xs,ys)
        super().__init__(width=512, height=512,visible=False)

    def on_draw(self):
        self.clear()

你的代码之所以不工作,是因为你不能在方法外部引用Frontend类的实例。如果你只想要一个Frontend类的实例,你可以这样做:

class Frontend:
    window = pyglet.window.Window()
    def __init__(self):
        ...
    @window.event
    def on_draw():
        ...

撰写回答