2

というクラスがEnemyあり、複数のタイプの敵が必要です。それぞれEnemyが異なる動きの振る舞いをします。たとえば、プレーヤーに向かってまっすぐに移動したり、特定の距離を維持したりします。私が知りたいのは、できれば1つのクラスで複数の異なる振る舞いをする最も簡単な方法は何ですか?

私の現在のアイデアは、を使用しswitch、すべての動作を 1 つのメソッドに含めることです。

public class Enemy
{
     public int health;
     public int damage;
     // etc etc

     public void Move(string type)
     {
        switch(type)
        {
             case "charge":
                  chargeMove();
                  break;
             case "maintain":
                  maintainMove();
                  break;
        }
     }

     private void chargeMove()
     {
          //stuff
     }

     private void maintainMove()
     {
          //stuff
     }

     //all the behaviors
}

私が知りたいのは、このようにすべてを 1 つの関数にまとめた方が良いですか、それとも から継承する敵の種類ごとに新しいクラスを作成する方が良いEnemyですか? IList特定の関数を使用するためにキャストを行う必要がなく、すべての敵を に適切に格納できるように、1 つのクラスに保持することをお勧めします。

アドバイスをいただければ幸いです。

編集:すべての応答に感謝します。Alastair によって提案されたインターフェイス メソッドを使用すると思います。

4

5 に答える 5

2

戦略パターンが役に立ちそうです。

敵の種類ごとに新しいクラスを用意するというあなたの提案は良いものだと思います。List<Enemy>それらはすべてそのクラスから継承されるため、さまざまな敵タイプのさまざまなオブジェクトをすべて単一に格納できます。

クラスを抽象化することも考えられますが、Enemy必須ではありません。

また、リスト内の特定のオブジェクトの特定のタイプを本当に知る必要がある場合は、typeofまたはisを使用できます。

于 2013-03-21T04:21:12.687 に答える
2

これはGamedev.stackexchange.comサイトの方が適しているかもしれませんが、何らかの構成の使用を検討することをお勧めします。

動きの説明を記述するインターフェイスを定義します。例えば

public interface IMovementBehavior
{
    void Move(Enemy enemy);
}

そのため、さまざまな動きを説明するさまざまな動作がいくつかあります。例えば。

public class ChargingMovementBehavior : IMovementBehavior { ... }
public class MaintainingMovementBehavior : IMovementBehavior { ... }

したがって、敵のコンストラクターは次のような定義を持つ可能性があります。

public Enemy(IMovementBehavior movementBehavior) { ... }

これは、敵のクラスをすべての異なる移動ビヘイビアーで埋める必要なく、さまざまな移動ビヘイビアーを簡単にプラグインおよびプラグアウトできることを意味します。

これは、コンポーネント ベースのエンティティと呼ばれます。

于 2013-03-21T04:29:21.887 に答える
1

デリゲートを使用:

public delegate void DoSth();

実行時に、このデリゲートを別のインスタンスに関連付けます。

こちらの msdn リファレンスを参照してください。

于 2013-03-21T04:19:34.743 に答える
1

同じインターフェイスから派生する複数のクラスを作成します。インターフェイス タイプのリストを引き続き取得できます。これは、ポリモーフィズムが役立つ典型的な例です。以下のようなもの:

interface iEnemy
{
    public void Move();
}

class Troll : iEmeny
{
    public void Move()
    {
       Console.WriteLine("troll moves!");
    }
}

class Ogre : iEmeny
{
    public void Move()
    {
       Console.WriteLine("ogre moves!");
    }
}

次に、コードでこれを行うことができます:

List<iEnemy> enemies = new List<iEnemy>();
enemies.Add(new Troll());
enemies.Add(new Ogre());

foreach(iEnemy e in enemies)
{
    e.Move();
}
//Output would be:
//troll move!
//ogre move!

これにより、エンティティは拡張のために開いているが、変更のために閉じられている必要があることを示す、開いている/閉じているプリンシパルに従うこともできます。

于 2013-03-21T04:25:39.400 に答える
0

派生クラスを使用します。同じメソッドが呼び出されたときに異なる動作を提供するためです。

キャストしたくない場合は、基本クラスですべてのメソッドを定義します。派生クラスが特定のメソッドをオーバーライドしない場合、基本クラスで定義されている動作が取得されますが、それを呼び出さなくても問題はありません。また、typeof などを使用したくない場合は、整数の「type」フィールドを使用することもできます。

public enum EnemyType
{
    Zombie,
    Vampire
}

public class Enemy
{
    private EnemyType mType;

    protected Enemy(EnemyType type) { mType = type; }

    public EnemyType getEnemyType() { return mType; }

    public void walk() { }

    public void attack() { }

    public void eatBrains() { }
}

public class Vampire : Enemy
{
    public Vampire : base(EnemyType.Vampire) { }

    public void walk()
    {
        // walk like a vampire
    }

    public void attack()
    {
        // attack like a vampire
    }

    // don't bother implementing eatBrains() because vampires don't do this
    // calling code will use getEnemyType() and won't bother call our eatBrains() method anyway
}
于 2013-03-21T04:28:43.770 に答える