1

我正在创建一个游戏,它具有键盘事件和一个事件系统,可以在其上注册功能,并且需要返回两个列表(任意大小):游戏时间事件列表和真实列表时间事件(按此顺序)。赛事主办方随后将

我正在重构代码以执行此操作。在以前的系统中,事件会手动将它们的事件与主游戏时间/实时事件队列合并。

我正在尝试重构在按下/释放键时触发所有事件的代码。当前代码:

class KeyReleaseEventRunner
    GameEvents = []
    RealEvents = []        

    def __call__(self):
        """Run all relevant events."""

        # Run key-specific key release events
        KeyReleaseEvent[self.key]()

        # Run key-specific key toggle events
        KeyToggleEvent[self.key](False)

        # Run generic key release events
        KeyReleaseEvent(self.key)

        # Run generic key toggle events
        KeyToggleEvent(self.key, False)

我的问题是如何合并这些函数中的所有事件。

有没有更简单易读的方法来做到这一点?:

    def __call__(self):
        """Run all relevant events."""

        # Run key-specific key release events
        g_events, r_events = KeyReleaseEvent[self.key]()
        self.GameEvents.extend(g_events)
        self.RealEvents.extend(r_events)

        # Run key-specific key toggle events
        g_events, r_events = KeyToggleEvent[self.key](False)
        self.GameEvents.extend(g_events)
        self.RealEvents.extend(r_events)

        # Run generic key release events
        g_events, r_events = KeyReleaseEvent(self.key)
        self.GameEvents.extend(g_events)
        self.RealEvents.extend(r_events)

        # Run generic key toggle events
        g_events, r_events = KeyToggleEvent(self.key, False)
        self.GameEvents.extend(g_events)
        self.RealEvents.extend(r_events)

        # Events must maintain sorted-ness
        self.GameEvents.sort()
        self.RealEvents.sort()

我不想在 KeyReleaseEventRunner 上创建方法(这种情况在其他几个地方,并且经常使用局部变量而不是 GameEvents/RealEvents)。

更一般地说,让这些函数返回两个列表是否有更好的解决方案?

可以区分 g_events 和 r_events 中的事件。

编辑:

为了消除关于对象既可调用又可索引的任何混淆:

可能值得注意的是,实例Event是注册函数的接口,调用时会调用所有注册的对象。 KeyToggleEventKeyReleaseEvent(and also KeyPressEvent) 是 的子类的实例Event,其他模块可以通过它注册键特定事件(通过注册到KeyReleaseEvent[key])和非键特定事件(通过注册到KeyReleaseEvent)。

4

1 回答 1

2

我想知道索引和调用组合的原因是它似乎使您的界面过于复杂。这可能不是您想听到的,但我不禁觉得您最好使用关键字参数而不是索引来指定事件子集。然后你可以创建一个参数列表和一个对象列表,并遍历它们。像这样的东西:

arg_list = [{'key':self.key, 'foo':False}, {'key':self.key}, ... ]
handlers = [KeyReleaseEvent, KeyToggleEvent, ...]
for handler, args in zip(arg_list, handlers):
    g_events, r_events = handler(*args)
    self.GameEvents.extend(g_events)
    self.RealEvents.extend(r_events)
self.GameEvents.sort()
self.RealEvents.sort()

或者更简洁:

gevents_revents = [handler(*args) for handler, args in zip(arg_list, handlers)]
all_gevents, all_revents = zip(*gevents_revents)
self.GameEvents.extend(e for sublist in all_gevents for e in sublist)
self.RealEvents.extend(e for sublist in all_revents for e in sublist)

当然,您仍然可以使用当前设置执行类似的操作。但我担心它会不那么优雅。

我还认为您应该考虑为您的事件队列使用不同的数据结构。您是否考虑过使用优先级队列而不是简单的列表,例如由 提供的优先级队列heapq?这将允许您避免重复的 (O(n log n)) 排序。单独的插入和删除将是 O(log n),这比使用列表的简单方法 (O(n)) 更好,但比更谨慎的方法 (O(1)) 更差。实际上,随着时间的推移,您会分散工作,因为单个项目会从队列中删除,而不是一次性完成所有工作。但是你仍然会得到 O(n) 合并!

这是否是正确的方法取决于您自己的情况。(例如,如果您需要查看未来事件的顺序,这不是最好的方法。)如果您有兴趣,我可以写更多关于此的内容,但基本思想是您可以使用heapq.heapify(O( n)) 而不是sort(O(n log n))。

arg_list = [{'key':self.key, 'foo':False}, {'key':self.key}, ... ]
handlers = [KeyReleaseEvent, KeyToggleEvent, ...]
for handler, args in zip(arg_list, handlers):
    g_events, r_events = handler(*args)
    self.GameEvents.extend(g_events)
    self.RealEvents.extend(r_events)
heapq.heapify(self.GameEvents)
heapq.heapify(self.RealEvents)

然后从队列中取出最高优先级的项目:

next_game_event = heapq.heappop(self.GameEvents)
于 2012-05-19T01:39:47.747 回答