1

キーボードイベントと、関数を登録できるイベントシステムがあり、ゲーム時のイベントのリストと実際のイベントのリストの2つのリスト(任意のサイズ)を返す必要があるゲームを作成しています。タイムイベント(この順序で)。その後、イベントランナーは

これを行うためにコードをリファクタリングしているところです。以前のシステムでは、イベントは手動でイベントをメインのゲーム時間/リアルタイムイベントキューとマージしていました。

キーが押された/離されたときにすべてのイベントをトリガーするコードをリファクタリングしようとしています。現在のコード:

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の代わりにローカル変数を使用することがよくあります)。

より一般的には、これらの関数が2つのリストを返すようにするためのより良い解決策はありますか?

g_eventsとr_eventsのイベントを区別することができます。

編集:

オブジェクトが呼び出し可能であり、索引付け可能であるという混乱を解消するには、次のようにします。

Eventのインスタンスは、関数を登録するためのインターフェイスであり、呼び出されると、登録されているすべてのオブジェクトを呼び出す ことに注意してください。KeyToggleEventおよびKeyReleaseEvent(および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))よりも劣っています。事実上、個々のアイテムが一度にすべてを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 に答える