EDIT:以下、私は何度も繰り返し使ってきた基本的なイベントメッセージングシステムについて説明します。そして、両方の学校プロジェクトはオープンソースでウェブ上にあります。 http://sourceforge.net/projects/bpfat/には、このメッセージングシステムの2番目のバージョンがあります(もう少し詳しく)。システムの詳細については、お楽しみください。
私は一般的なメッセージングシステムを作成し、それをPSPとエンタープライズレベルのアプリケーションソフトウェアでリリースされたいくつかのゲームに導入しました。メッセージングシステムのポイントは、使用する用語に応じて、メッセージやイベントを処理するために必要なデータのみを渡すことであり、オブジェクトはお互いに知る必要はありません。
A
struct TEventMessage
{
int _iMessageID;
}
class IEventMessagingSystem
{
Post(int iMessageId);
Post(int iMessageId, float fData);
Post(int iMessageId, int iData);
// ...
Post(TMessageEvent * pMessage);
Post(int iMessageId, void * pData);
}
typedef float(*IEventMessagingSystem::Callback)(TEventMessage * pMessage);
class CEventMessagingSystem
{
Init ();
DNit ();
Exec (float fElapsedTime);
Post (TEventMessage * oMessage);
Register (int iMessageId, IEventMessagingSystem* pObject, FObjectCallback* fpMethod);
Unregister (int iMessageId, IEventMessagingSystem* pObject, FObjectCallback * fpMethod);
}
#define MSG_Startup (1)
#define MSG_Shutdown (2)
#define MSG_PlaySound (3)
#define MSG_HandlePlayerInput (4)
#define MSG_NetworkMessage (5)
#define MSG_PlayerDied (6)
#define MSG_BeginCombat (7)
#define MSG_EndCombat (8)
そして今、説明のビット:これを達成するために使用されるオブジェクトのリストの下に迅速に実行はの線に沿って何かです。最初のオブジェクトTEventMessageは、メッセージングシステムによって送信されたデータを表す基本オブジェクトです。デフォルトでは、あなたはあなたができることを期待していたメッセージを受け取っているかどうかを確認するために、常にメッセージのIDを送信します(通常はデバッグでのみ行います)。
次は、コールバックの実行中にメッセージングシステムがキャストに使用する汎用オブジェクトを与えるInterfaceクラスです。さらに、これは、メッセージングシステムに異なるデータ型をPost()するための使いやすいインタフェースを提供します。
その後、我々はコールバック型のtypedefを持っています。単にインターフェイスクラスの型のオブジェクトを期待して、TEventMessageポインタを渡します...オプションでパラメータconstを作ることができますが、Iveはトリクルアップ処理をスタックデバッグなどのメッセージングシステムのようなものです。
最後に、CEventMessagingSystemオブジェクトがコアにあります。このオブジェクトには、コールバックオブジェクトスタック(またはリンクされたリストまたはキュー、またはデータを格納したい)の配列が含まれています。上には示されていないコールバックオブジェクトは、オブジェクトへのポインタと、そのオブジェクトを呼び出すメソッドを維持する必要があります(また、それらによって一意に定義されます)。 Register()を実行すると、メッセージIDの配列位置にあるオブジェクトスタックにエントリが追加されます。 Unregister()を実行すると、そのエントリが削除されます。
これは基本的には..ここには、すべてがIEventMessagingSystemとTEventMessageオブジェクトについて知る必要があるという規定があります。このオブジェクトはそれを頻繁に変更するべきではなく、呼び出されるイベントによって決定されるロジックに不可欠な情報の部分だけを渡すべきです。この方法では、プレイヤーはマップや敵を直接知り、イベントをオフに送信する必要はありません。管理対象オブジェクトは、それについて何かを知る必要なしに、より大きいシステムにもAPIを呼び出すことができます。
例:敵が死亡したときに、効果音を鳴らしたい場合。 IEventMessagingSystemインターフェイスを継承するサウンドマネージャがあると仮定すると、TEventMessagePlaySoundEffectまたはそのilkの何かを受け入れるメッセージングシステムのコールバックを設定します。 Sound Managerは、サウンドエフェクトが有効になっているときにこのコールバックを登録します(オン/オフ機能を簡単にするためにすべてのサウンドエフェクトをミュートする場合はコールバックの登録を解除します)。次に、敵のオブジェクトもIEventMessagingSystemから継承させ、TEventMessagePlaySoundEffectオブジェクトを組み込みます(メッセージIDにMSG_PlaySound、次に再生するサウンドエフェクトのIDが必要です)。これはint IDまたはサウンドの名前ですエフェクト)、単にポスト(& oEventMessagePlaySoundEffect)を呼び出します。
これは実装されていない非常に単純なデザインです。すぐに実行できるのであれば、TEventMessageオブジェクトをバッファリングする必要はありません(主にコンソールゲームで使用したもの)。マルチスレッド環境にある場合、これは、別々のスレッドで実行されているオブジェクトとシステムが互いに通信するための非常に明確な方法ですが、処理時にデータを利用できるようにTEventMessageオブジェクトを保持する必要があります。
これ以外の変更は、データをPost()にする必要があるオブジェクトに対してのみ、IEventMessagingSystemで静的メソッドセットを作成して継承する必要がないようにすることができます(アクセスやコールバック機能Post()呼び出しには直接的には必要ありません)。
MVCについて言及したすべての人にとって、これは非常に良いパターンですが、さまざまな方法でさまざまなレベルで実装できます。私が専門的に取り組んでいる現在のプロジェクトは、約3回以上のMVCセットアップです。アプリケーション全体のグローバルMVCがあり、それぞれのMVとCも組み込みのMVCパターンです。ここでは、ビューに入る必要性を排除してMのほぼすべてのタイプを処理するのに十分な一般的なCを作成する方法を説明します。
たとえば、オブジェクトが「死んでいる」場合は再生したい場合がありますサウンドエフェクト.. TEventMessageから継承し、サウンドエフェクトIDを追加するTEventMessageSoundEffectのようなサウンドシステム用の構造体を作成します(プリロードされたInt、またはsfxファイルの名前ですが、システムでトラッキングされます) )。次に、すべてのオブジェクトは、適切なDeathノイズを持つTEventMessageSoundEffectオブジェクトをまとめてポスト(& oEventMessageSoundEffect)を呼び出す必要があります。あなたがサウンドマネージャの登録を解除したいだろうか(音がミュートされていないと仮定すると、...オブジェクト
EDIT:以下のコメントに関してのビット、これを明確にする:メッセージを送信または受信する どれでもオブジェクトがちょうどする必要がありますIEventMessagingSystemインターフェースについて知っていて、これはEventMessagingSystemが他のすべてのオブジェクトを知る必要がある唯一のオブジェクトです。これがデタッチメントを提供するものです。メッセージを受信したいオブジェクトは単純にRegister(MSG、Object、Callback)それから、オブジェクトがPost(MSG、Data)を呼び出すと、それはそれを知っているインターフェイスを介してEventMessagingSystemに送信し、EMSは登録された各オブジェクトにイベントを通知します。プレイヤーはMSG_PlaySound、MSG_Respawnなどを呼び出すことで、それらのメッセージを聞いているものがそれらに作用するようにすることができます。ゲームエンジン内の異なるシステムへの抽象APIとしてのPost(MSG、Data)。
ああ!私に指摘されたもう1つのこと..私が上で説明したシステムは、与えられた他の答えのObserverパターンに適合します。だから、より一般的な説明をして欲しいのであれば、もう少し理解してください。
これが役立ちます。
+1徹底的な説明はありますが、私も発言をしています。プレイヤーはイベントを送るためにマップ*について知る必要はないと述べましたが、あなたの例は、死にかけている敵は、通知する必要があるプログラムの一部。私は単に「ただ死んでしまった」というメッセージを送信し、メッセージングシステムにこのイベントに興味のあるリスナー(サウンド再生、スコアの更新など)を通知させることを期待していました。このようにして、どのエンティティも単一のイベント(サウンドを再生し、スコアを上げる)のためにたくさんのメッセージを送信する必要があるように見えます。それとも間違っていたのですか? – Groo
@Groo私は自分の応答を十分に短くすることができなかったので、私は上記の私の答えにそれを編集しました。 – James
こんにちは、あなたの答えから5年以上経ちましたが、単純なpubsubのアイデアを探していたときにこのポストが出てきました。私はソースをダウンロードしました。コーディング標準を除いて、 C++は2005年以来少し進歩していますが、このコードは非常に興味深いものです。私はC#のゲームにEMSスケルトンを使用しました。あなたが3人でやったことは本当に驚くほど難しくて、もっと学ぶことを願っています! –