我有一个名为Enemy
的课程,我希望有多种类型的敌人。每个Enemy
都会有不同的移动行为,例如,一个人可能直接向玩家移动,一个可能保持一定的距离等等。我想知道的是,有多种不同行为的最简单方法是什么,最好是在一个班级?
我目前的想法是使用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
的敌人类型创建一个新类?我宁愿将它保留在一个类中,这样所有的敌人都可以很好地存储到IList
中,而不需要进行任何演员来使用任何特定的函数。
任何建议都将受到赞赏。
编辑:感谢所有的回复,我想我将使用Alastair提出的接口方法。答案 0 :(得分:2)
听起来像Strategy Pattern会很有用。
我认为你对每种敌人类型都有一个新课程的建议很好。您仍然可以将不同敌人类型的所有不同对象存储在一个List<Enemy>
中,因为它们都从该类继承。
您还可以考虑将Enemy
类视为抽象类,但这不是必需的。
答案 1 :(得分:2)
虽然这可能更适合Gamedev.stackexchange.com网站,但您可能需要考虑使用某种合成方式。
定义描述移动描述的界面。 E.g。
public interface IMovementBehavior
{
void Move(Enemy enemy);
}
那么你会有许多描述不同动作的不同行为。 例如
public class ChargingMovementBehavior : IMovementBehavior { ... }
public class MaintainingMovementBehavior : IMovementBehavior { ... }
所以你的敌人构造者可能会有一个像:
这样的定义public Enemy(IMovementBehavior movementBehavior) { ... }
这意味着您可以轻松插入和移出不同的移动行为,而无需使用所有不同的移动行为填充您的敌人类。
答案 2 :(得分:1)
答案 3 :(得分:1)
我会创建多个派生自同一界面的类。您仍然可以拥有接口类型列表。这是polymorphism派上用场时的一个主要例子。如下所示:
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!
这也允许您遵循open/closed principal,其中声明实体应该开放以进行扩展但已关闭以进行修改。
答案 4 :(得分: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
}