让我们说我有一个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();
}
}
实施此更好的方法是什么?你有什么建议吗? 似乎对于新武器中的每一个不同的动作,我需要在最主要的武器类中实现一个功能,我不认为这是一个好主意...
答案 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
成为武器可以做的各种事物的组合。如果几种武器表现相似,他们可以分享策略,而不是在各种武器之间复制代码。