web-dev-qa-db-ja.com

ゲームプログラマーは、AI、ネットワーク、プレイアンドパスモードで再利用するクラスをどのように設計しますか?

2人用ゲームの場合、対戦相手はネットワーク、CPU自体、または同じマシンでターンごとにプレイするあなたの近くにいる可能性があります。

再利用のためにクラスをどのように設計しますか?私も同じような状況にあり、そのような複雑なゲームを作成した経験はありません。

しかし、これは私が考えたことです、

私がプレイヤーオブジェクトである場合は、GameManagerまたはGameEngine Singletonとのみ対話する必要があり、そこからゲームのステータスに関するさまざまな通知を受け取ります。

私は対戦相手がどこに誰であるかは気にしません。このGameManagerはゲームモードによって異なり、gameNetworkManagerと対話するか、AIが対戦相手のプレイ内容を教えてくれます。

私たちがプレイして[同じマシンでターンバイターン]をパスするシナリオはわかりません。

簡潔だが明確な説明、または少なくとも同様のリソースへのリンクを期待しています。

5

明確な答えはなく、ゲームのクラス設計は非常に幅広いトピックです。ただし、非常に一般的な2つの落とし穴について説明します。

  1. 継承を使用してゲームエンティティのポリモーフィズムをモデル化するのは魅力的です。そのため、BaseEntityPlayerCharacterなどを取得し、それらの移動方法をモデル化するためのメソッドをそれらに提供します。 、描き、何をすべきかを決定し、他の世界と交流します。ただし、これは非常に緊密な結合を可能にし、正確に再利用を優先しません。より良いアプローチはコンポジションです:Entityクラスを非ポリモーフィックにしますが、さまざまな側面を説明するためにポリモーフィックメンバーの束を与えます。 Brain(動作を決定します。これはHumanPlayerBrainAIBrainNetworkBrainなどにすることができます)、Appearance(適切なモデル/スプライトを選択し、必要に応じてアニメーション化します)、Physics(エンティティの物理モデルのプロパティを記述)。これらはそれぞれ独自のクラス階層を持っていますが、それ以外の点ではほとんどが互いに独立しており、必要に応じてそれらを混合して一致させることができます。
  2. 自己更新エンティティを作成するのも魅力的で、多くの入門ゲームチュートリアルでもこれを推奨しています。 tick()メソッドを呼び出すたびに独自の位置を更新するボールはエレガントなソリューションのように聞こえますが、相互作用がより複雑になるとすぐに、厄介な問題に直面します-異なるタイプの100のエンティティが同時に動いている?衝突のチェックを担当するのは誰ですか。衝突が見つかった場合、2つのオブジェクトのどちらが「アクティブ」オブジェクトで、どれが「パッシブ」オブジェクトですか? a.collideWith(b)、またはb.collideWith(a)ですか?解決策は、すべてのエンティティをほとんどパッシブにすることです。それらは単にアクセサーを公開してそれらの物理プロパティ(位置、サイズ、質量、慣性など)をクエリおよび更新し、全体のGamePhysicsオブジェクトはすべてのオブジェクトのチェックと更新を担当します。衝突ハンドラーはworld.collide(a, b)になり、完全に簡単になりました。

そして、別の注意点:ゲームステートをシングルトンにすることは論理的な決定のように見えますが、一度に1つのゲームステートに制限されます。これには2つの重要な欠点があります。

  1. クライアント/サーバーアーキテクチャが必要な場合、サーバーは一度に1つのゲームしか実行できません。
  2. ゲームの状態に依存するあらゆるものを単体テストすることは難しくなります。

個人的には、ゲームの状態を別のオブジェクトとして渡すことを好みます。これのもう1つの利点は、ゲームの状態の一部のみを、残りの部分を操作する必要のないオブジェクトに渡すことができることです。たとえば、オブジェクトのrender()メソッドはゲームロジックをまったく変更しないことになっています。 constとして渡すことができます。物理部分はグラフィックス関連の処理を行うことは想定されていないため、リソースマネージャーへの参照を渡しません。これにより、潜在的な相互依存関係の数が少なくなり、複雑さが軽減されます。

18
tdammers