イベントハンドラに夢中になることはできますか?私は自分のデザインで「間違った方法」で進んでいますか?


12

私は、イベントハンドラが本当に好きだと決めたと思います。分析の麻痺に少し苦しんでいるかもしれませんが、デザインを扱いにくくしたり、デザインの決定に対する他の予期せぬ結果にぶつかったりすることを心配しています。

私のゲームエンジンは現在、パンニングオーバーヘッドカメラで基本的なスプライトベースのレンダリングを行っています。私のデザインは次のようになります。

SceneHandler

SceneListenerインターフェイスを実装するクラスのリストが含まれます(現在はSpriteのみ)。ティックごとにrender()を呼び出し、onCameraUpdate()を送信します。SceneListenersへのメッセージ。

InputHandler

ティックごとに1回入力をポーリングし、単純な「onKeyPressed」メッセージをInputListenersに送信します。SceneHandlerインスタンスを保持し、updateCamera()をトリガーするCamera InputListenerがあります。入力内容に基づいたイベント。

AgentHandler

ティックごとにエージェント(AI)でデフォルトアクションを呼び出し、登録されている新しいイベントがないかスタックをチェックし、必要に応じて特定のエージェントにディスパッチします。

そのため、シーン内を移動し、基本的なステアリング動作を使用して移動できる基本的なスプライトオブジェクトがあります。私は衝突の検出に着手しましたが、これは私の設計が進んでいる方向が良いかどうかわからないところです。多数の小さなイベントハンドラを用意するのは良い習慣ですか?ある種のCollisionHandlerを実装しなければならないという自分のやり方を想像する。

AI、衝突の更新、および1つのクラスでの他のエンティティの相互作用を処理する、より統合されたEntityHandlerを使用した方が良いでしょうか?それとも、どんな種類のイベントに基づいてメッセージを相互に渡す多くの異なるイベント処理サブシステムを実装するだけでいいのでしょうか?これらすべてのサブイベントハンドラーを調整するだけの責任を負うEntityHandlerを作成する必要がありますか?

InputHandlerやSceneHandlerなど、場合によっては、これらが非常に特殊なタイプのイベントであることを認識しています。ゲームコードの大部分は入力を気にせず、大部分は純粋にシーンのレンダリングで発生する更新を気にしません。したがって、これらのシステムの分離は正当であると感じています。ただし、私はこの質問を具体的にゲームロジックタイプイベントに近づいています。

回答:


21

イベントベースの設計では、主にReactorの設計パターンを実装します。

コンポーネントの設計を開始する前に、そのようなパターンの制限を確認する必要があります(これに関する多くの情報を見つけることができます)。

何よりもまず問題なのは、ハンドラーがすぐ戻らなければならないことです。何よりも GUIベースのフレームワークやJavaScriptベースのアプリケーションでseriusを使用したすべての人がよく知っている必要があることです。

かなり複雑なすべてのアプリケーションを開発するとき、遅かれ早かれ、時間を要する複雑な仕事をするハンドラーに直面するでしょうます。

これらの場合、2つの状況を区別できます(必ずしも相互に排他的ではありません)。

複雑なイベント関連の責任と複雑なイベント関連の責任。

複雑なイベント関連の責任:

最初のケースでは、1 つのコンポーネントハンドラーに多くの責任マージしました。たとえば、イベントへの応答で実行されるアクションが多すぎたり、実行中の同期があります。

この場合の解決策は、ハンドラーを(必要に応じて異なるオブジェクト内の)異なるハンドラー分割し、処理コードを直接呼び出すのではなく、ハンドルでイベントを発生させることです。これにより、イベントキューにイベントを追加した後にプライマリハンドラーが返されるため、優先度の高いイベントを以前に管理できるようになります。

別の解決策は、外部エンティティがイベントを発生させ、他のユーザーが興味がある場合にサブスクライブできるようにすることです(タイミングイベントは、一般化できる最も単純な例です)。

複雑なイベントに関係のない責任:

2番目のケースは、本質的な複雑さがある場合に発生しますイベント後に実行するアクションにます。たとえば、イベント後にフィボナッチ数を計算する必要があります。

ここで、Reactorパターンは基本的に失敗します。フィボナッチ生成アルゴリズムを、次のステップをトリガーするために終了時にイベントを発生させる小さなチャンクに分割する価値はほとんどありません。

ここでの解決策は、リアクターにスレッドデザインを混在させることです。良いニュースは、複雑さが本質的な場合(つまり、適切なセクションを読んでいる場合)、 Reactor関連の残りのコンポーネントについてほとんど、または何も知らない必要があります。

このような状況に対処するには、柔軟なスレッドプールでジョブキューを採用すると便利です。

ハンドラーは、長いアクションを開始する必要がある場合、そのアクションをジョブユニットカプセル化して、ジョブキューに入れます。このカプセル化されたアクションには、リアクタスレッドへのイベントをトリガーする手段が必要です。ジョブキューマネージャは、独自のスレッドまたはリアクタスレッドで実行され、「newJob」イベントに反応する場合があります。

ジョブキューマネージャーは次のことを行います。

  • プールが1つのスレッドを提供できる場合、そのスケジュールアルゴリズムを使用して、フレキシブルスレッドプールからスレッドにジョブユニットを割り当てます(空きスレッドがあるか、新しいスレッドの作成が許可されます)

  • プール自体をリッスンして、ジョブユニットが終了したかどうかを確認します。これにより、スレッドを回復して、保留中のユニットがもう1つあれば実行できます。

イベント起動メカニズムを使用して、ジョブユニットはイベントをトリガーして、完了、更新状態、警告、エラー、または必要なときに通知します。柔軟なスレッドプールは、システム全体をハングさせるデッドスレッドを回避しながら、リソースの適切な使用を保証します。ジョブキューを使用すると、一貫した量の計算リソースが必要になることがわかっているため、異なる種類のアクションに割り当てる優先度を選択できます。


3
非常に徹底しているため+1。好奇心reader盛な読者のためのいくつかのリンクは素晴らしいでしょう。
サムホセバー

1

ほとんどの場合、他のオプションよりもイベントを使用すると、速度と分散化を改善できます。たくさんのイベントを利用できるなら、ぜひ行ってみてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.