2

我有一个班级Enemy,我想有多种类型的敌人。每个Enemy都会有不同的移动行为,例如一个可能会直接向玩家移动,一个可能会保持一定的距离等。我想知道的是,拥有多种不同行为的最简单方法是什么,最好是在一个类中?

我目前的想法是使用 a switch,并将所有行为包含在一个方法中

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
}

我想知道的是,将所有内容保留在这样的一个函数中,还是为每个继承自的敌人类型创建一个新类更好Enemy?我更愿意将它保留在一个类中,以便所有敌人都可以很好地存储到 aIList中,而无需我进行任何强制转换来使用任何特定功能。

任何意见,将不胜感激。

编辑:感谢所有回复,我想我会使用 Alastair 提出的接口方法。

4

5 回答 5

2

听起来策略模式会很有用。

我认为您为每种 Enemy 类型设置一个新班级的建议是一个不错的建议。您仍然可以将不同敌人类型的所有不同对象存储在一个单独的对象中,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 等,你仍然可以有一个整数“类型”字段。

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 回答