继承,需要建议

时间:2017-07-12 00:17:03

标签: c# inheritance

让我们说我有一个ai或玩家,我希望他能够使用不同的武器。 我的武器设计:

public class Weapon()
{
    public virtual void FireWeapon(){} // this is useless for melee weapons
    public virtual void SwingMelee(){} // this is useless for guns
    public virtual void Reload(){} // this is also useless for melee weapons
}

然后在ai控制器类中,我只需调用我希望他做的函数。 这是丑陋的部分(我认为)...... 控制器类有一个列表,其中包含一些不同的武器和正在使用的武器。

public class WeaponController
{
   private List<Weapon> someWeapons;
   private Weapon aWeapon;
   public void Main()
   {
      if(/*"Some action or a button click" &&*/ aWeapon.CanSwingMelee() )
         aWeapon.SwingMelee(); 
      if(/*"Some action or a button click" &&*/ aWeapon.CanReload() )
         aWeapon.Reload();
   }
}

实施此更好的方法是什么?你有什么建议吗? 似乎对于新武器中的每一个不同的动作,我需要在最主要的武器类中实现一个功能,我不认为这是一个好主意...

3 个答案:

答案 0 :(得分:2)

游戏中对象的能力可以用界面表示;您可以通过尝试强制转换到界面来检查是否存在功能。而且,这些接口可以重叠,例如,近战和远程武器可能都有Attack方法。

例如:

public interface IWeapon
{
    void Attack();
}

public interface IRangedWeapon
{
    bool IsInRange(ITargetable target);
}

public interface IRequiresAmmunition
{
    void Reload();
    int  AmmoRemaining { get; set; }
}

public class Sword : IWeapon
{
    public virtual void Attack() { //code }
}

public class Rifle : IWeapon, IRequiresAmmunition, IRangedWeapon
{
    public virtual void Attack() { //code }
    public virtual void Reload() { //code }
    public virtual int  AmmoRemaining { get { } set { } }
    public virtual bool IsInrange (ITargetable target) { //code }
}

public class LaserGun: IWeapon, IRangedWeapon
{
    public virtual void Attack() { //code }
    public virtual bool IsInrange (ITargetable target) { //code }
}


public class WeaponController
{
   private List<IWeapon> someWeapons;
   private IWeapon aWeapon;
   private ITargetable currentTarget;

   public void Weapon_OnUse()
   {
       if (!currentTarget.IsHostile) return;

       if (this.IsInMeleeRange(currentTarget))
       {
           aWeapon.Attack();
           return;
       }
       var w = aWeapon as IRangedWeapon;

       if (w != null && w.IsInRange(currentTarget)
       {
           aWeapon.Attack();
           return;
       }

       context.HUD.Warn("Out of range");

   }

   public void Weapon_OnReload()
   {
       var w = aWeapon as IRequiresAmmunition;
       if (w != null) 
       {
            w.Reload();
            context.HUD.DisplayAmmo(w.AmmoRemaining);
       }
   }
}

答案 1 :(得分:1)

这似乎是abstract类和继承的用途:

public abstract class Weapon {
    public abstract void Attack();
    public abstract void Reload();
}

public class MeleeWeapon : Weapon {
    public override void Attack() {
        // swing sword
    }
    public override void Reload() {
        // ignore reload
    }
}
public class GunWeapon : Weapon {
    public override void Attack() {
        // fire gun
    }
    public override void Reload() {
        // load weapon from inventory
    }
}

public class WeaponController {
    private List<Weapon> someWeapons;
    private Weapon aWeapon;
    public void Main() {
        if (/*"Some action or a button click" */)
            aWeapon.Attack();
        else if (/* some other button click */)
            aWeapon.Reload();
    }
}

答案 2 :(得分:0)

我不推荐一种方法,要求您为每个新行为创建新接口并检查武器的类型。这样的事情怎么样:

(这是非常草稿。)

public abstract class Weapon
{
    protected Weapon(WeaponCommandStrategy[] commandStrategies)
    {
        CommandStrategies = commandStrategies;
    }

    protected IEnumerable<WeaponCommandStrategy> CommandStrategies { get; }

    public void Use(WeaponCommand command)
    {
        var strategy = CommandStrategies.FirstOrDefault(c => c.Command == command);
        strategy?.Execute();
    }
}

public enum WeaponCommand
{
    Fire,
    Swing,
    Reload
}

public abstract class WeaponCommandStrategy
{
    public WeaponCommand Command { get; private set; }

    protected WeaponCommandStrategy(WeaponCommand command)
    {
        Command = command;
    }

    public abstract void Execute();
}

现在,您可以以WeaponCommandStrategy的各种实例的形式向武器提供您想要的任何行为。如果命令被发送到武器,它将执行它。如果它不支持命令,则忽略它。您可以向武器添加属性,从而暴露可用命令,以便显示可用命令列表。

public class Sword : Weapon
{
    // Perhaps use dependency injection here
    public Sword() 
        : base(new WeaponCommandStrategy[] { new SwordSwingStrategy() })
    {
    }
}

public class SwordSwingStrategy : WeaponCommandStrategy
{
    public SwordSwingStrategy() : base(WeaponCommand.Swing) { }

    public override void Execute()
    {
        // Do whatever it does
    }
}

这基本上使Weapon成为武器可以做的各种事物的组合。如果几种武器表现相似,他们可以分享策略,而不是在各种武器之间复制代码。