ゲームエンジンでのイベント駆動型通信:はいまたはいいえ?


62

私はGame Coding Completeを読んでおり、著者はゲームオブジェクトとモジュール間のイベントドリブン通信を推奨しています。

基本的に、すべての生きているゲームアクターは、内部イベントメッセージングシステムを介して主要モジュール(物理、AI、ゲームロジック、ゲームビューなど)と通信する必要があります。つまり、効率的なイベントマネージャーを設計する必要があります。設計が不適切なシステムは、特にモバイルプラットフォームに影響を与えるCPUサイクルを消費します。

これは実証済みで推奨されるアプローチですか?使用するかどうかはどのように決定すればよいですか?


こんにちはジェームズ、答えてくれてありがとう。この本では、イベント駆動型の通信が非常に複雑なシステムであり、CPUリソースを大幅に消費しているように見えますが、気に入っています。
文海佐取

それを回答に入れ、スタックオーバーフローに関する回答として私が出したイベントメッセージングシステムの高レベルの概要へのリンクに追加しました。楽しい!ただ、どのような一部の人々は、複雑な考慮すると、:)である必要はありませんことを覚えておいてください
ジェームズ

:あなたは、C ++ 11使用して行うだけでなく、この答えを確認することができますstackoverflow.com/a/22703242/2929762
user2826084

libuv最近、成功したイベントライブラリとして登場しました。(Cにあります。Node.jsが最も有名なユースケースです。)
アンコ14年

回答:


46

これは、提案されているように、私のコメントを完全な回答に拡大したものです。

はい、シンプルでシンプル。コミュニケーションが必要であり、「まだそこにいるのか?」-typeポーリングが必要です。他の何かを行うべきかどうかを確認するために、一般的に時間を無駄にします。代わりに、指示されたことに反応させることができます。さらに、オブジェクト/システム/モジュール間の明確に定義された通信経路により、並列セットアップが大幅に向上します。

Stack Overflowのイベントメッセージングシステムの概要を説明しました。私はそれを学校からプロのゲームタイトルに使用し、今ではゲーム以外の製品を使用し、コースのたびにユースケースに適合させています。

編集どのオブジェクトがメッセージを取得するかをどのように知っているかについてのコメントの質問に対処するには:オブジェクト自体にRequestイベントについて通知する必要があります。あなたのEventMessagingSystem(EMS)が必要になりますRegister(int iEventId, IEventMessagingSystem * pOjbect, (EMSCallback)fpMethodToUseForACallback)だけでなく、マッチングUnregister(のためのユニークなエントリ作るiEventIdオブジェクトポインタとコールバックのアウト)。このように、オブジェクトがRegister()システムでできるメッセージについて知りたいとき。イベントについて知る必要がなくなると、Unregister()。明らかに、これらのコールバック登録オブジェクトのプールと、リストからオブジェクトを追加/削除する効果的な方法が必要です。(私は通常、自己順序付け配列を使用しました;必要に応じてサイズを適切にシフトする未使用オブジェクトと配列のプールスタックの間の独自の割り当てを追跡するという素晴らしい方法です)。

編集:更新ループとイベントメッセージングシステムを備えた完全に機能するゲームの場合、古い学校のプロジェクトをチェックアウトすることをお勧めします。上記のリンクされたStack Overflowポストもそれを参照しています。


こんにちはジェームズ、内部イベントメッセージングシステムについてもっと考えているので、エンジンに追加のコストを追加する必要はないと思います。たとえば、画面上に50個のオブジェクトがあり、そのうち5個だけが動作を変更することになっている場合、従来のシステムでは、50個のオブジェクトすべてが、アクションを実行する必要があるかどうかを確認するために、考えられるすべてのアクションをチェックする必要がありました。ただし、イベントメッセージングを使用すると、特定のアクションが変更された5つの対象に5つのメッセージのみが送信されます。それは時間を節約するアプローチのように見えます。
文海。佐取

上記の回答でリンクされたシステムの動作方法は、オブジェクトが必要なメッセージを聞くためにのみ登録するということです。プレイヤーが直接やり取りできるものを「アクティブ化」し、聞いているものの数を約10程度に抑えます。すべてのこのタイプのシステムは、「まだそこにいるのか」よりも「賢い」はずです。ポーリングシステム、および少なくとも通信に関する限り、エンジンのオーバーヘッドを削減する必要があります。
ジェームズ

私を混乱させるイベント駆動型システムに関連するものが1つあります。すべてのオブジェクトがメソッドの事前定義セット(OnUpdate()、OnMove()、OnAI()、OnCollisionCheck()...)を定期的に呼び出す従来のシステムでは、すべてのオブジェクトは状態の確認と管理を担当します。イベント駆動型システムでは、すべてのオブジェクトのマスターシステムのチェッキング条件が存在し、イベントが検出されたものにメッセージを送信する必要があります。私にとって、これは可能なオブジェクトの状態を標準化し、独自のオブジェクト動作を作成する自由を制限します。本当?
文海。佐取

Observerパターンは、ポーリングの典型的な代替手段です。en.wikipedia.org/wiki/Observer_pattern
リケット

1
@この情報はまだこれがかなり発生した場合、あなたはスピードのためにそれを最適化したいと思うでしょう覚えているなど、から描画する登録オブジェクトのプールを持って、登録に関しては:)人々を助けているグラッドhamlin11
ジェームズ

22

私の意見では、あなたはあなたのゲームを作り始めて、あなたが快適なものを実装するべきだと思います。そのようにすると、MVCを使用している場所もあれば、そうでない場所もあります。他のイベントではなく、いくつかの場所のイベント。いくつかの場所を構成しますが、他の場所を継承します。いくつかの場所をきれいにデザインし、他の場所を凝ったデザインにします。

そして、それは大丈夫です、あなたが終わったとき、あなたは実際にゲームを持っているでしょう、そしてゲームはメッセージ受け渡しシステムよりずっとクールだからです。


2
こんにちはジョー、あなたの答えをありがとう、私はそれが好きです。あなたは、アプローチを人為的に推し進める必要はないと信じています。動作すると思うようにアプリケーションを設計する必要があります。後で動作しない場合は、単純にやり直します。
文海。佐取

これがシステムが存在する理由です。多くの人があなたが言ったことだけを行い、悪夢を目撃し、より良い方法が必要だと言った。間違いを繰り返すか、そこから学び、それをさらに進めることができます。
user441521

16

より良い質問は、どのような選択肢がありますか?物理学、AIなどのモジュールが適切に分割されたこのような複雑なシステムでは、これらのシステムを他にどのように調整できますか?

メッセージの受け渡しは、この問題に対する「最良の」解決策のようです。私は今、代替案を考えることができません。しかし、実際にメッセージを渡す例はたくさんあります。実際、オペレーティングシステムは、いくつかの機能にメッセージパッシングを使用しています。ウィキペディアから:

メッセージもプロセス間通信の手段と同じ意味で一般的に使用されます。他の一般的な手法はストリームまたはパイプで、データは代わりに一連の基本データ項目として送信されます(仮想回路の上位バージョン)。

(プロセス間通信は、オペレーティングシステム環境内のプロセス(つまり、プログラムの実行インスタンス)間の通信です)

オペレーティングシステムとして十分であれば、おそらくゲームとしても十分でしょうか?他にも利点がありますが、メッセージパッシングに関するウィキペディアの記事で説明します。

また、スタックオーバーフローに関する質問「プログラム内でメッセージを渡すためのデータ構造?」、読み直したいかもしれません。


こんにちはリケット、答えてくれてありがとう。ゲームオブジェクトが相互に通信できるようにするために、他にどのような方法を使用できるか尋ねました。私の頭に浮かぶのは、直接的なメソッド呼び出しです。それほど柔軟ではありませんが、一方で、イベントメッセージの生成、受け渡し、読み取りなどを回避することはコレクトです。ハイエンドゲームについてではなく、モバイルプラットフォームについて引き続き話します。オペレーティングシステムは内部メッセージングシステムを積極的に使用します。ただし、わずかな遅延でも中断を引き起こすリアルタイムで実行するようには設計されていません。
文海。佐取

この質問をしばらく公開しておきましょう。それを閉じる前に、私はより多くの意見を収集したいと思います。
文海佐取

通常、直接メソッド呼び出しは、互いに呼び出すクラスを結合します。これは、互換性があると想定されるコンポーネントに分離されたシステムには適していません。結合性の低い直接メソッド呼び出しを容易にするパターンがいくつかあります(たとえば、MVCの「コントローラー」部分は、結合しない限り、基本的にこの目的を果たし、モデルのビューのクエリを容易にします)。サブシステム間でゼロカップリングを持つシステム(または少なくとも私が知っている唯一の方法)。
リケット

ああ、それでパターンの議論を始めました。このプログラミング手法について少し聞いたことがあります。今、私はパターンとは何かを理解し始めました。アプリケーション設計の見方はまったく異なります。同じコードを使用してすべてのオブジェクトをチェックしながら、オブジェクトを自主的に制御します。オブジェクトを確認した後、それに応じて属性を設定します。
文開.Satori

1
「データ構造...」質問には驚くべき答えがあります。あなたが選んだ答えと付随するNebula3の記事は、私が今まで見たサイズのゲームエンジンアーキテクチャの最良の説明です。
-deft_code

15

通常、メッセージは次の場合にうまく機能します。

  1. メッセージを送信するものは、受信しても問題ありません。
  2. 送信者は、受信者からすぐに応答する必要はありません。
  3. 単一の送信者をリッスンする複数の受信者が存在する場合があります。
  4. メッセージはまれにまたは予期せずに送信されます。(言い換えれば、すべてのオブジェクトが1フレームごとに「更新」メッセージを取得する必要がある場合、メッセージは実際にはあまり買いません。)

あなたのニーズがそのリストと一致すればするほど、より適切なメッセージになります。非常に一般的なレベルでは、彼らはかなり良いです。ポーリングやその他のグローバルなソリューションとは異なり、CPUサイクルを無駄にしないという良い仕事をしています。彼らはコードベースの一部を分離するのが素晴らしいです。これは常に役に立ちます。


4

ジェームズとリケットからのこれまでの素晴らしい答えは、注意のメモを追加することだけです。メッセージパッシング/イベントドリブン通信は、確かに開発者の武器の重要なツールですが、簡単に使いすぎてしまう可能性があります。ハンマーを持っていると、すべてが釘のように見えます。

絶対に、100%、タイトルの周りのデータの流れを考え、サブシステムから別のサブシステムに情報が渡される方法を完全に認識する必要があります。場合によっては、メッセージの受け渡しが明らかに最適です。他の場合、1つのサブシステムが共有オブジェクトのリストを操作する方が適切な場合があり、他のサブシステムも同じ共有リストで操作できるようになります。その他の多くのメソッド。

どのサブシステムがどのデータにアクセスする必要があるか、いつアクセスする必要があるかを常に把握しておく必要があります。これは、並列化と最適化の能力に影響を与えるだけでなく、エンジンのさまざまな部分が密接に絡み合った場合に、より陰湿な問題を回避するのに役立ちます。データの不要なコピーを最小限に抑え、データレイアウトがキャッシュの使用にどのように影響するかを考える必要があります。これらのすべてが、それぞれの場合に最適なソリューションを提供します。

そうは言っても、私がこれまで取り組んできたほとんどすべてのゲームには、強固な非同期メッセージパッシング/イベント通知システムがありました。複雑で急速に変化する設計ニーズに直面しても、簡潔で効率的な保守可能なコードを作成できます。


良い追加情報については+1。こんにちは、MrCranky、ありがとう。あなたが言うことによると、モバイルゲームでもイベントメッセージングシステムを検討する価値があるはずです。ただし、計画は見落とされるべきではなく、メッセージングシステムが使用される場所を非常によく考慮する必要があります。
文開.Satori

4

まあ、私はこの投稿がかなり古いことを知っていますが、私は抵抗できませんでした。

私は最近、ゲームエンジンを構築しました。レンダリングと物理演算に3dパーティライブラリを使用しますが、エンティティとゲームロジックを定義および処理するコア部分を作成しました。

エンジンは確実に従来のアプローチに従います。すべてのエンティティに対して更新関数を呼び出すメイン更新ループがあります。衝突は、エンティティのコールバックによって直接報告されます。エンティティ間の通信は、エンティティ間で交換されるスマートポインターを使用して行われます。

原始的なメッセージシステムがあります。それは、エンティティの小さなグループのみを処理してメッセージをエンジン化します。これらのメッセージは、更新リストを混乱させる可能性があるため、ゲームインタラクションの終了時に処理することが望ましいです(例:エンティティの作成または破棄)。そのため、各ゲームループの終わりに、メッセージの小さなリストが消費されます。

原始的なメッセージシステムにもかかわらず、私はシステムの大部分が「更新ループベース」であると言います。

まあ。このシステムを使用した後、私はそれが非常にシンプルで、高速で、よく組織されていると思います。ゲームロジックは表示され、エンティティ内に自己完結しています。メッセージキューのような動的ではありません。私の意見では、イベントシステムはゲームロジックに不必要な複雑さをもたらし、ゲームコードの理解とデバッグを非常に難しくするので、イベントドリブンにしたくありません。

しかし、私のような純粋な「更新ループベース」システムにもいくつかの問題があると思います。

たとえば、ある瞬間に、あるエンティティが「何もしない」状態になり、プレーヤーが近づいているなどの状況を待っている場合があります。これらのほとんどの場合、エンティティはプロセッサ時間を無駄に消費しないため、エンティティをオフにし、特定のイベントが発生したときにオンにすることをお勧めします。

そのため、次のゲームエンジンでは、別のアプローチを採用します。エンティティは、更新、描画、衝突検出などのエンジン操作のために自身を登録します。これらの各イベントには、実際のエンティティのエンティティインターフェイスのリストが分離されています。


エンティティはモンスターコードベースになり、ゲーム内のあらゆる種類の複雑さで管理が難しくなります。最終的にそれらを結合し、機能を追加または変更するのは面倒です。機能を小さなコンポーネントに分割することで、機能の保守と追加が簡単になります。次に、これらのコンポーネントがどのように通信するかが問題になりますか?答えは、プリミティブデータを引数に渡しながら、あるコンポーネントから別のコンポーネントの機能を上げるイベントです。
user441521

3

はい。これは、ゲームシステムが互いに通信するための非常に効率的な方法です。イベントを使用すると、多くのシステムを分離し、互いの存在を知らなくても個別にコンパイルすることもできます。これは、クラスをより簡単にプロトタイプ化でき、コンパイル時間が短縮されることを意味します。さらに重要なことは、依存関係の混乱の代わりにフラットなコード設計になることです。

イベントのもう1つの大きな利点は、ネットワークまたは他のテキストチャネルを介して簡単にストリーミングできることです。後で再生するために記録できます。可能性は無限大。

別の利点:同じイベントをリッスンする複数のサブシステムを持つことができます。たとえば、すべてのリモートビュー(プレイヤー)は、エンティティ作成イベントに自動的にサブスクライブし、各クライアントでエンティティをスポーンできます。イベントを使用しなかった場合、さらに多くの作業が行われることを想像してください。Update()どこかに電話をかけるかview->CreateEntity、ゲームロジックから電話をかける必要があります(ビューに関する知識と必要な情報が属していない場合)。イベントなしでその問題を解決することは困難です。

イベントを使用すると、無制限の種類の無数のオブジェクトをサポートするエレガントで分離されたソリューションを取得できます。これらのオブジェクトはすべて、イベントにサブスクライブし、ゲームで何かが発生したときにその処理を実行できます。それがイベントが素晴らしい理由です。

詳細と実装はこちら


素晴らしい点ですが、一方的です。私は常に一般性を疑っています:イベントのユースケースはありますか?
アンコ14年

1
アンチユースポイント:直接的な対応が絶対に必要な場合。何らかのイベントで実行したいことが、常に同じスレッド内で直接実行される場合。通話の完了を遅らせる可能性のある外部遅延がまったくない場合。線形依存関係しかない場合。複数のことを同時に行うことはめったにありません。node.jsを見ると、すべてのio呼び出しはイベントベースです。Node.jsは、イベントが100%正しく実装された1つの場所です。
user2826084 14年

イベントシステムは非同期である必要はありません。コルーチンを使用して非同期をシミュレートし、必要なときに同期を取得できます。
user441521

2

私が見たものから、メッセージングに完全に基づいたエンジンを持つことはあまり一般的ではないようです。もちろん、ネットワーキング、GUI、およびその他のようなメッセージングシステムに非常に適したサブシステムがあります。ただし、一般的には、考えられるいくつかの問題があります。

  • ゲームエンジンは大量のデータを処理します。
  • ゲームは高速でなければなりません(20〜30 FPSが最小である必要があります)。
  • 多くの場合、何かが行われたかどうか、またはいつ行われるかを知る必要があります。

「可能な限り効率的でなければならない」という一般的なゲーム開発者のアプローチでは、このようなメッセージングシステムはそれほど一般的ではありません。

ただし、先に進んで試してみてください。そのようなシステムには確かに多くの利点があり、コンピューティング能力は今日安く利用できます。


これに同意するかどうかはわかりません。別の方法は、無駄なポーリングです。イベントにのみ応答するのが最も効率的です。はい、まだいくつかのポーリングが発生し、イベントが発生しますが、イベント指向のイベントも多数あります。
user441521

私もこれに同意しません。イベントメッセージングは​​サブシステム間通信用に設計されているため、扱うデータゲームエンジンの量はほとんど関係ありません。ゲームオブジェクトは、他のゲームオブジェクトと直接通信しないでください(ただし、オブジェクト内のカスタムイベントハンドラーは例外になる場合があります)。この比較的少数のサブシステムとその「関心」の領域のために、マルチスレッドエンジンで適切に設計されたメッセージングバックボーンのパフォーマンスコストは無視できます。
イアンヤング
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.