1

在此之前,我必须说我不像其他语言那样非常熟悉 python 编程。我对寻找其他解决方案非常(也)很恼火,所以提前感谢您的帮助。

我喜欢在空闲时间制作 Roguelike 游戏,所以我尝试了多种方法来使用 C++、C、C#、HTML5 等为我自己的游戏做自己的“引擎”实现和引擎。我以前从未使用过LibTCOD 因为我永远无法让它在 C++ 中工作,唉,这是我最喜欢的编程语言,这是一个我现在不打算谈论的问题,因为它在 C++ 线程中。

可怕的是,LibTCOD 看起来很棒,但提及和精确的文档太少,所以我几乎只能独自工作。最近几天我做了一个小python包来轻松管理python和windows的LibTCOD功能,并使主游戏代码尽可能小。

我尝试添加的最终实现是将主游戏循环传递给线程,处理每个基本游戏功能(如键盘/鼠标更改和屏幕更新),并通过函数调用运行它。

一切正常......但不是在第一个循环步骤之后,因为它冻结了一切并停止工作。

基本上这是有问题的代码:

def ioHandler(l):
    lastx = 0
    lasty = 0
    lastk = None
    c = 0
    noEvent = 0
    casted = False
    while not tcod.console_is_window_closed():
        l.acquire()
        try:
            tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS|tcod.EVENT_MOUSE,key,mouse)
        finally:
            l.release()
        if mouse.lbutton_pressed:
            casted = True
            l.acquire()
            try:
                onClick(mouse, 'left')
            finally:
                l.release()
        if mouse.rbutton_pressed:
            casted = True
            l.acquire()
            try:
                onClick(mouse, 'right')
            finally:
                l.release()           
        if mouse.cx != lastx or mouse.cy != lasty:
            casted = True
            l.acquire()
            try:
                lastx = mouse.cx
                lasty = mouse.cy
                onMouseMove(mouse)
            finally:
                l.release()
        if key != lastk:
            casted = True
            l.acquire()
            try:
                lastk = key
                onKeyPress(key)
            finally:
                l.release()
        if not casted: noEvent += 1
        l.acquire()
        try:
            onTickFrame(c+1)
        finally:
            l.release()

那里使用的大多数变量都是为了更清晰的调试理解目的,(即使它冻结了“干净”功能)所以我必须把它们放在那里。

上面的'def'是从这里调用的:

def main_loop():
    l = threading.Lock()
    tr = threading.Thread(target=ioHandler, args=(l,))
    #tr.daemon=True
    tr.start()

对于“事件”系统,我在互联网上找到了这个:

class Event:
    handlers = set()
    def __init__(self):
        self.handlers = set()

    def handle(self, handler):
        self.handlers.add(handler)
        return self

    def unhandle(self, handler):
        try:
            self.handlers.remove(handler)
        except:
            raise ValueError("Handler is not handling this event, so cannot unhandle it.")
        return self

    def fire(self, *args, **kargs):
        for handler in self.handlers:
            handler(*args, **kargs)

    def getHandlerCount(self):
        return len(self.handlers)

    __iadd__ = handle
    __isub__ = unhandle
    __call__ = fire
    __len__  = getHandlerCount

注意:我正在使用 Python 2.7,这是唯一适用于该库的版本,真可惜。

我认为事件系统可能是主要问题。再次阅读代码,我想我也应该对 while 条件应用锁,因此对整个循环,还是没有必要?是否以正确的方式应用了锁?还是我应该使用其他方法使线程正常工作?

顺便提一下,如果主游戏循环在没有线程的主脚本上执行,则一切正常,但是当作为线程调用时一切都失败,或者即使它不是线程本身,而是从“外部”调用,就像在包,所以它不能是图书馆的问题(我认为)。

我不得不说,我只在 Python 中使用过 LibTCOD,因为我不能让它只在它上面工作(至少在 Windows 上)。如果有帮助,我已经看到 python 库的代码只是原始 C 库的“绑定”,所以理解 python 代码并不是什么大问题。对于最后一个陈述,我认为这也是 python 线程的问题,还是我错了?如果我可以做些什么来修复线程工具,请帮助我!

谢谢你们!我希望我的谈话没有让你感到厌烦。

4

1 回答 1

1

您的示例中缺少足够的内容,以至于我无法使其及时运行,因此我没有适合您的已知解决方案,但我确实有一些建议:

  1. 如果同一个线程将释放获得它的锁,我建议使用RLock() 而不是 Lock()

l = threading.RLock()

  1. 为了使代码更简洁,错误探测更少,我建议使用锁提供的上下文管理器:

代替:

l.acquire():
try:
    tcod.sys_check_for_event(
        tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse)
finally:
    l.release()

尝试:

with l:
    tcod.sys_check_for_event(
        tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse)
  1. 至于还有什么应该锁定的问题。如果不了解所有数据结构,这很难回答,但一般来说,任何将在多个线程中使用的东西都应该被锁定。
于 2017-01-04T05:03:23.347 回答