編集:以下に、私が何度も使用した基本的なイベントメッセージングシステムについて説明します。そして、両方の学校のプロジェクトがオープンソースであり、ウェブ上にあることに気づきました。このメッセージングシステムの2番目のバージョン(およびかなり多く)はhttp://sourceforge.net/projects/bpfat/にあります。システムの詳細については、以下をお読みください。
私は一般的なメッセージングシステムを作成し、それをPSPでリリースされたいくつかのゲームといくつかのエンタープライズレベルのアプリケーションソフトウェアに導入しました。メッセージングシステムのポイントは、使用する用語に応じて、メッセージまたはイベントの処理に必要なデータのみを渡すことです。これにより、オブジェクトはお互いを知る必要がなくなります。
これを達成するために使用されるオブジェクトのリストの簡単な要約は、次のようなものです。
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にすることができますが、以前はトリクルアップ処理を使用しました。メッセージングシステムのスタックデバッグなど。
最後に、コアとなるのはCEventMessagingSystemオブジェクトです。このオブジェクトには、コールバックオブジェクトスタック(またはリンクリストまたはキュー、あるいはデータを保存する場合)の配列が含まれています。上に示されていないコールバックオブジェクトは、オブジェクトへのポインタとそのオブジェクトを呼び出すメソッドを維持する必要があります(そしてそれによって一意に定義されます)。Register()を実行すると、オブジェクトスタックのメッセージIDの配列位置の下にエントリが追加されます。Unregister()を実行すると、そのエントリが削除されます。
基本的にはそれだけです。これには、IEventMessagingSystemとTEventMessageオブジェクトについてすべてが知る必要があるという規定があります...しかし、このオブジェクトはそれほど頻繁に変更されるべきではなく、呼び出されるイベントによって指示されるロジックに不可欠な情報の部分のみを渡します。このように、プレイヤーはイベントをマップに送信するためにマップや敵について直接知る必要はありません。管理対象オブジェクトは、APIについて何も知らなくても、より大規模なシステムに対してAPIを呼び出すことができます。
例:敵が死んだとき、効果音を鳴らしたい。IEventMessagingSystemインターフェイスを継承するサウンドマネージャーがあると仮定すると、TEventMessagePlaySoundEffectまたはそのようなものを受け入れるメッセージングシステムのコールバックを設定します。サウンドマネージャーは、サウンドエフェクトが有効になっている場合にこのコールバックを登録します(または、オン/オフ機能を簡単にするためにすべてのサウンドエフェクトをミュートする場合は、コールバックの登録を解除します)。次に、敵のオブジェクトもIEventMessagingSystemから継承し、TEventMessagePlaySoundEffectオブジェクトをまとめます(メッセージIDにはMSG_PlaySoundが必要で、再生するには効果音のIDが必要です(int IDまたはサウンドの名前)。効果)そして単にPost(&oEventMessagePlaySoundEffect)を呼び出します。
これは、実装のない非常に単純な設計です。すぐに実行できる場合は、TEventMessageオブジェクト(私が主にコンソールゲームで使用したもの)をバッファリングする必要はありません。マルチスレッド環境にいる場合、これは、別々のスレッドで実行されているオブジェクトとシステムが相互に通信するための非常に明確な方法ですが、処理時にデータを利用できるようにTEventMessageオブジェクトを保持する必要があります。
もう1つの変更は、Post()データのみが必要なオブジェクトの場合です。IEventMessagingSystemに静的なメソッドのセットを作成して、それらから継承する必要がないようにすることができます(これは、直接ではなく、アクセスとコールバック機能を容易にするために使用されます) --Post()呼び出しに必要)。
MVCに言及するすべての人にとって、これは非常に優れたパターンですが、さまざまな方法でさまざまなレベルで実装できます。私が専門的に取り組んでいる現在のプロジェクトは、約3倍以上のMVCセットアップであり、アプリケーション全体のグローバルMVCがあり、各MVとCも自己完結型のMVCパターンです。だから私がここでやろうとしたのは、ビューに入る必要なしにほぼすべてのタイプのMを処理するのに十分な汎用性のあるCを作成する方法を説明することです...
たとえば、オブジェクトが「死ぬ」ときにサウンドエフェクトを再生したい場合があります。TEventMessageから継承してサウンドエフェクトIDを追加するTEventMessageSoundEffectのようなサウンドシステムの構造体を作成します(プリロードされたInt、またはsfxファイルの名前。ただし、システムで追跡されます)。次に、すべてのオブジェクトは、適切なデスノイズを含むTEventMessageSoundEffectオブジェクトをまとめて、Post(&oEventMessageSoundEffect);を呼び出す必要があります。オブジェクト..サウンドがミュートされていないと仮定します(サウンドマネージャーの登録を解除する必要があります。
編集:以下のコメントに関してこれを少し明確にするために:メッセージを送信または受信するオブジェクトは、IEventMessagingSystemインターフェイスについて知る必要があります。これは、EventMessagingSystemが他のすべてのオブジェクトについて知る必要がある唯一のオブジェクトです。これはあなたに分離を与えるものです。メッセージを受信したいオブジェクトは、単に登録(MSG、オブジェクト、コールバック)します。次に、オブジェクトがPost(MSG、Data)を呼び出すと、それを認識しているインターフェイスを介してEventMessagingSystemに送信し、EMSは登録されている各オブジェクトにイベントを通知します。他のシステムが処理するMSG_PlayerDiedを実行するか、プレーヤーがMSG_PlaySound、MSG_Respawnなどを呼び出して、それらのメッセージをリッスンしているものがそれらに作用するようにすることができます。Post(MSG、Data)は、ゲームエンジン内のさまざまなシステムへの抽象化されたAPIと考えてください。
おー!私に指摘されたもう一つのこと。私が上で説明したシステムは、与えられた他の答えのオブザーバーパターンに適合します。したがって、私のものをもう少し意味のあるものにするために、より一般的な説明が必要な場合は、それはそれに良い説明を与える短い記事です。
これがお役に立てば幸いです。