0

私の質問を詳しく説明すると、特定の状況は次のとおりです。

たとえば、メンバ データとして異なる統計 ( 、 など) を持つクラスを持つシミュレーションまたはゲーム プロジェクトがあり、一定Monsterの基本統計 ( 、など)を持つ任意の数の異なるタイプのモンスターが必要な場合、このクラスを使用する必要がある 3 つの方法を参照してください。hitPointsRemainingAttackDamageMaxHPSpeed

  1. コード全体で Monster オブジェクトを使用するために使用されるインターフェイスを持つ実際のクラス (" Monster" など)
  2. さまざまな種類のモンスターの実際の「データ」。(概念的に可能なサブクラス? 正しい解決策ではないことは確かですが) 例: ゴブリン、ドラゴン、サイクロプスなど
  3. キャラクターがゲーム内で遭遇したさまざまなモンスターを表す実際のインスタンス化さMonsterれたオブジェクト (いつでも同じタイプの複数のインスタンスが存在する可能性があります)

ほとんどのデザイナーがこれをどのように実装するのか疑問に思っていました。私の考えは次のとおりです。

Monster-開発が進むにつれ、想定されるすべてのタイプのモンスターに対してクラスを作成し、次に新しいサブクラスを作成することは意味がありません。これは、特に、異なるモンスター タイプの数が数百単位で異なり、各タイプの違いが新しいサブクラスを保証するのに十分なほど大きくない場合は、非常に厄介で保守不可能なソリューションのように思えます。

-むしろ、私の解決策は次のようになりMonsterます。このテーブルは、プロジェクトの開発中にいつでも追加できます。

  1. テーブルからMonsterオブジェクトにデータをロードする関数を作成します。

  2. ファイルを解析し、MonsterManagerインスタンス化さMonsterれたオブジェクトの静的またはメンバー ベクトルを作成し、ファイル内のテーブルからすべての「基本」統計情報を入力して (つまり、開始時のヒットポイントなど)

  3. Monsterあるタイプの新しいオブジェクトをインスタンス化して誰かの軍隊に追加したり、誰かに会わせたりしたいときはいつでもMonster、ベクトルから (ランダムに、または何らかの決定要因を介して) 選択し、新しいMonsterオブジェクトを作成し、それをベクトルからコピーします。

これは解決策として理にかなっていますか、それとも私は昼食に出かけていますか? これが良い解決策ではない場合、より良い方法はありますか?

その他の補足質問:

-ベクトルに保持されるモンスター データに対して別のクラスを作成することは理にかなっていますか? MonsterData上記によってベクターに組み込まれるクラスを呼び出すことができると思いましたMonsterManager。多くのMonsterDataオブジェクトの特性はモンスターのMonster種類( MaxHP 、速度など) によって決定され、その他のもの (CurrentHP、任意のランダム変数など)MonsterMonster

-モンスターが出現するレベルを示すエントリをテーブルに追加し、MonsterManager初期化関数で特定のレベルのすべてのモンスターのみを一度にロードしてメモリフットプリントを縮小するなどのことができるため、この方法は最適化できると思いました) -私はこれに を使用していないので、テキスト文字列を保存することは、オブジェクトの「タイプ」enumを識別する手段として意味がありますか? Monsterおそらく、のベクトルからコピーされたMonster(または) へのポインタの方がよいでしょうか?MonsterDataMonsterManager

ここで最も理にかなっているゲームのアナロジーを使用しましたが、どのような状況でもこの種のものに最適な設計パターンを知りたいです。

みんな、ありがとう!

4

2 に答える 2

4

継承は、データ値の変更ではなく、動作の変更/追加に使用する必要があります。あなたの例では、各モンスターは一連の属性 (HP、攻撃など) によって定義されているようで、ゲーム内でさまざまなモンスター タイプをインスタンス化する必要があります。これには継承は本当に必要ありません。

あなたのMonsterDataクラスは正しい方向に進んでいます。これが私がそれを行う方法です(ほとんどの場合、より意味のあるクラスの名前が異なるだけです):

// This is what you called MonsterData
// It describes how to create a monster of a specific type
public class MonsterDescription {
  private String type;   // eg. "Goblin"
  private int maxHitPoints;
  private int speed;
  ...
}

// This is an "active" instance of a monster
public class Monster {
  private int currentHitPoints;
  ...

  // static factory method
  public static Monster create(MonsterDescription desc) {
    ...
  }
}

// This is kind of what you called MonsterManager
// Contains a collection of MonsterDescription, loaded from somewhere
public class MonsterDescriptionRepository {
  // finds the description for a given type of monster
  public MonsterDescription find(String type) {
    ...
  }
}

そして、新しいモンスターをインスタンス化する方法は次のとおりです。

MonsterDescription desc = repository.find("Goblin");
Monster monster = Monster.create(desc);
于 2012-07-14T08:37:15.970 に答える
2

データローダーのアプローチはあなたの問題に合っているようです - それは簡単に拡張可能になります. さまざまな機能のサブクラスを作成することをお勧めします-たとえば、ドラゴンを処理するがゴブリンやサメを処理しない FlyingMonster サブクラスを作成すると、飛行/実行/潜水できる単一のモンスタークラスを避けることができます;)

あなたの最後の質問は、外部データのキーイングに関するものでした-これには、ポインターアプローチが最適だと思います:

  • それはユニークです
  • デバッグに役立ちます
  • 必要に応じて、ストアから保存された値を使用できます
  • 祖先への「is_a」接続が表示されます

注:この段階では、パフォーマンスの問題を「気にする」必要はないと思います(メモリフットプリントを減らすためにメモリにロードします)。通常、設計が壊れるためです。

于 2012-07-14T08:38:51.190 に答える