ゲームのイベントスケジューラを作成したいのですが、基本的にはゲームイベントのトリガーをスケジュールできるようにしたいのです。これは、1回限りのトリガー、または定期的なトリガー(5秒ごとにトリガーイベント "E_BIG_EXPLOSION" ...)になります。
これはシングルトンを使用するのに適した場所かもしれないと思われがちですが、シングルトンは非常に邪悪で、病気のように広がる傾向があります...
この場合、シングルトンの使用を避けるためにどのような設計を提案しますか?
ゲームのイベントスケジューラを作成したいのですが、基本的にはゲームイベントのトリガーをスケジュールできるようにしたいのです。これは、1回限りのトリガー、または定期的なトリガー(5秒ごとにトリガーイベント "E_BIG_EXPLOSION" ...)になります。
これはシングルトンを使用するのに適した場所かもしれないと思われがちですが、シングルトンは非常に邪悪で、病気のように広がる傾向があります...
この場合、シングルトンの使用を避けるためにどのような設計を提案しますか?
回答:
メッセージの送受信を許可する非常に明確に定義されたインターフェイスのセットが必要です。EventSchedulerへの参照を与えるのは簡単です。そうでない場合、またはイベントスケジューラを "多すぎる"特殊型に渡す必要があると思われる場合は、より大きな設計上の問題を抱えている可能性があります(乱雑な依存関係、シングルトンは悪化せず、解決しない)。
スケジューラーを必要とするインターフェースに渡す手法は「依存性注入」の形式ですが、この場合、新しい依存性を注入するのではないことに注意してください。これは、システムにすでにある依存関係ですが、現在は(シングルトンの暗黙的な依存関係に対して)明示的な依存関係にしています。経験則として、明示的な依存関係は、より自己文書化されるため、より望ましいです。
また、イベントスケジューリングのコンシューマーを互いに分離することにより、柔軟性が高まります(すべてが必ずしも同じスケジューラーに関連付けられているわけではないため)。これは、ローカルクライアント/サーバーのセットアップまたは他の多くのオプションをテストまたはシミュレートするのに役立ちます-これらの他のオプションは必要ないかもしれませんが、それらから人為的に自分自身を制限するための努力を費やしていないことはプラスです。
編集:スケジューラーを渡すことについて私が言っているのはこれだけです:衝突への応答を担当するゲームコンポーネントがある場合、おそらく物理層の一部である衝突レスポンダーファクトリを介して作成されます。スケジューラインスタンスを使用してファクトリを構築する場合、ファクトリは作成したレスポンダにそのインスタンスを渡すことができ、それを使用してイベントを発生させる(または他のイベントをサブスクライブする)ことができます。
class CollisionResponderFactory {
public CollisionResponderFactory (EventScheduler scheduler) {
this.scheduler = scheduler;
}
CollisionResponder CreateResponder() {
return new CollisionResponder(scheduler);
}
EventScheduler scheduler;
}
class CollisionResponder {
public CollisionResponder (EventScheduler scheduler) {
this.scheduler = scheduler;
}
public void OnCollision(GameObject a, GameObject b) {
if(a.IsBullet) {
scheduler.RaiseEvent(E_BIG_EXPLOSION);
}
}
EventScheduler scheduler;
}
あなたのゲームオブジェクトモデルがわからないので、これは明らかにひどく不自然で単純化された例です。ただし、イベントスケジューラへの依存関係を明示的に示し、さらにカプセル化する可能性を示しています(レスポンダーが同じ概念レベルでより高いレベルの衝突応答システムと通信した場合、必ずしもレスポンダーにスケジューラーを渡す必要はありません)スケジューラを介してイベントを発生させることの要点を処理したファクトリこれは、個々のレスポンダ実装を、イベントディスパッチシステムの実装の詳細(衝突時に発生させる特定のイベントなど)から分離します。 - か否か)。
私はシングルトンも避ける傾向がありますが、シングルトンとして最も意味のあるオブジェクトがいくつかあり、中央メッセージングシステムもその1つです。私が聞いた暴言にもかかわらず、シングルトンは常に意図的に対処する必要があるため、グローバル変数/関数よりもはるかに優れています(グローバル値は単に空中から魔法のように表示されます)。
最終的にはすべてのメッセージの送信者と受信者が持っている必要があり、いくつかの共通の交点を、そしてそれはあなたのメッセージ送信者のそれぞれが直接メッセージ受信機について知っているのではなく、すべてに共通するシングルトンを持っていることによって切り離され、あなたのオブジェクトを保持するためにはるかに優れています。
他のアーキテクチャをイベントシステム用に考案できると確信していますが、特にイベントシステムを使用することは、システムを使用しないことに対する大きな勝利である場合、それを考え直すのは無駄な労力のように思えます。
編集:定期的なトリガーでディスパッチされる爆発イベントの特定の例については、中央イベントシステムではなく、他のオブジェクト(タレットガンまたはそれらの爆発を引き起こすものなど)でイベントをディスパッチします。ただし、これらのイベントは依然として中央イベントシステムにディスパッチされます。