【问题标题】:Performing different tasks according to the type of given data根据给定数据的类型执行不同的任务
【发布时间】:2020-04-26 15:29:24
【问题描述】:

我正在尝试创建一个具有武器系统的游戏,其中将有近战、火器等武器类型。我为数据创建了类,然后我将在另一个类中引用这些数据类并相应地执行任务(Fire、Reload 等)。

public abstract class WeaponData {
      public int damage;

      public abstract void Fire();
}

注意抽象的存在,我使用这个类作为基础,并使用每种武器都会有的常见东西。然后,我们将为继承上述此类的每种类型的武器创建类:

public class FirearmData : WeaponData {
     public SupplyData ammoTypeData;
     public int magazineSize;
     public AnimationClip reloadAnimation;

     public override void Fire() {
           // blablabla...
     }
}

这个类覆盖了 Fire() 方法并且还有一些其他不同的字段。这是另一个武器类型类:

public class MeleeWeaponData : WeaponData {
     public AnimationClip swingAnimation;

     public override void Fire() {
           // blablabla...
     }
}

到目前为止,我设法创建了这些类,但这并不意味着我将来不会创建更多像这两个这样的类,我把它留在这里是因为我发现这个系统无法工作.. .

所以我也有一个 Weapon 类,我将引用一个 WeaponData,它的方法会根据数据执行不同的任务。

public class Weapon {
     public WeaponData data;

     void Fire() {
         data.Fire();
     }

     void Reload() {
        // the problem is here;
     }
}

所以问题就在这里,我在这个类中包含了数据需要的所有可能方法,但是如果你问我这并不优雅,因为 WeaponData 将是 MeleeWeaponData,在这种情况下,它不需要Reload() 方法或整数杂志字段。我仍然可以通过做一些开关来检查数据的类型来使它工作。但是每当我碰巧创建了更多的数据类型时,我都必须每次都到这里并在 switch 中添加一条语句。而我不希望那样。

所以我想为此咨询泛型,例如:

public class Weapon<T> where T : WeaponData {

}

但是正如你告诉我的那样,这也不会让我能够获得 WeaponData 子类的字段......

你们能找出一个适合我的系统吗?我正在 Unity 上制作游戏,如果这意味着什么,我确实使用 ScriptableObjects 来处理数据。

【问题讨论】:

  • 因为您已将T 限制为X,但X 没有field2
  • field2 是字段,它需要一个实例......但这并不能回答你真正的问题。
  • 有没有办法访问它?不做 if (T is typeof(Y) something) 之类的事情?
  • @Masea 那对我来说是一个设计问题。如果您编辑您的问题以获取有关您正在尝试做什么的更多详细信息,也许我们可以建议一个更好的选择,但目前这似乎是一个 XY 问题(您试图通过做某事来解决问题 X,而这导致了问题 Y,但这根本不是 X 的真正解决方案,因此我们正在尝试解决错误的问题)。
  • 好的,谢谢你们,我会尝试编辑我的 OP 并包含更多关于我想要实现的目标的深入信息。

标签: c# unity3d generics constraints


【解决方案1】:

我建议你改用接口: 例如 IFireable、IReloadable。

interface IWeapon
{
    void Fire();
}

interface IReloadable
{
    void Reload();
}

实现你的 WeaponData ase

class WeaponData: IWeapon
{
    public int damage;
    public abstract Fire();
}

对于枪支,从 WeaponData 派生,并实现 IReloadable。

public class FirearmData : WeaponData, IReloadable
{
     public SupplyData ammoTypeData;
     public int magazineSize;
     public AnimationClip reloadAnimation;

     public override void Fire() 
     {
           // blablabla...
     }
     public void Reload() 
     {
           // Reload
     }
}

Fire MaleeData,仅派生自 WeaponData。

因此,在您的 Weapon 类中,检查武器的类型,如果它支持 IReloadable,则进行重新加载,否则,什么也不做。

public class Weapon {
     public WeaponData data;

     void Fire() {
         data.Fire();
     }

     void Reload() {
        if(data is IReloadable reloadableData)
        {
             reloadableData.Reload();
        }
        else
            // Do nothing.
     }
}


【讨论】:

  • 您能否为 Weapon 类中的 Reload() 方法提出其他建议?
  • 如果调用者可以直接访问武器数据,调用者只需要检查武器数据实例是否支持IReloadable.Reload,对吗?如果您有自动重新加载逻辑,例如,当弹匣为空时,执行重新加载,则可以将此逻辑添加到 FirearmData.Fire() 中。如果您需要玩家手动重新加载,则必须由代码的其他部分发起重新加载调用。
  • 所以,Weapon 类也应该有一个整数,称为杂志,它携带有多少子弹装入武器的信息。但是考虑到这个字段对于 MeleeWeaponData 来说不是必需的,它会一直留在那里。这个呢?
  • 我猜你的意思是“子弹”?子弹或弹药是枪支的概念,而不是武器的通用概念,因为有刀或剑不需要补充弹药,也没有“重新加载”的概念。我认为这里的问题是您将数据与操作分开。 (在 Weapon 类中,你有 WeaponData 字段、Fire 方法、Reload 方法)最好从武器类中去掉武器数据,或者我们可以说,IWeapon 接口?
【解决方案2】:

一个简单的解决方案是这样的:

public abstract class WeaponData
{
    public int damage;

    public abstract void Fire();

    public virtual void Reload()
    {
        return;
    }
}

然后在需要的地方覆盖 Reload():

public class FirearmData : WeaponData {
     public SupplyData ammoTypeData;
     public int magazineSize;
     public AnimationClip reloadAnimation;

     public override void Fire() {
           // blablabla...
     }

     public override void Reload() {
           // blablabla...
     }
}

在不存在的地方忽略它:

public class MeleeWeaponData : WeaponData {
     public AnimationClip swingAnimation;

     public override void Fire() {
           // blablabla...
     }
}

【讨论】:

  • 这样你就不会像使用虚拟一样使用它了。
  • @Masea 启发我。
  • 虚拟方法应该有一个初始和共同的任务。如果孩子想做与特定任务不同的事情,他们应该重写它。但是在您的代码中,它没有初始任务。
  • @Masea 当然可以,最初的任务是什么都不做。只有特殊情况需要更多,这从 FirearmData 中添加的大量字段就可以看出。
猜你喜欢
  • 2021-05-24
  • 1970-01-01
  • 2017-09-02
  • 1970-01-01
  • 2016-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多