unity c# 继承/泛型接口升级不同子类

Posted

技术标签:

【中文标题】unity c# 继承/泛型接口升级不同子类【英文标题】:Unity c# Inheritance / generic Interface to upgrade different subclasses 【发布时间】:2022-01-17 22:56:50 【问题描述】:

我正在尝试通过使用接口升级特定的大炮,我面临的问题是由于某种原因,函数被正确调用并且没有错误,但实际上参数没有“升级”为预计。

BaseWeapon.cs

public class BaseWeapon : MonoBehaviour


public new string name;
public int level = 1;
public int damage;
public int cost;
private BaseEnemy target;
public IDoDamage damageType;
public IDoUpgrade upgradeType;

public int TryDoDamage(BaseEnemy target, int damage)

    this.target = target;
    int dmg = (int)damageType?.DoDamage(target, damage);
    target.UpdateHealth();
    return dmg;

public void TryDoUpgrade(BaseCannon cannon)

    Debug.Log("Inside TryDoUpgrade SUCCESS");    // This debug works
    upgradeType?.DoUpgrade(cannon);
    Island.Instance.Spend(cannon.cost);

上述调试有效,按预期从播放器中减去金币。

DefCannon.cs我用它来实例化一个BaseCannon,它继承自BaseWeapon,带有自定义参数,这是默认的cannon,我也有一个FireCannon作为例子,它们都继承自BaseCannon , 而后者又继承自 BaseWeapon.:

public class DefCannon : BaseCannon

public void Init(int level)

    name = "Defcannon";
    this.level = level;
    cannonMat = Cannonballs.cbCannonMat["Default"];
    damage = 50 * level;
    ballMat = Cannonballs.cbMat["Default"];
    cbSpeed = Cannonballs.cbSpeed["Default"];
    minPrecision = 0.91f;
    maxPrecision = 1.11f;
    minReload = 0.5f;
    maxReload = 1.0f;
    damageType = new DefDamage(level);
    upgradeType = new DefUpgrade(this, level);


我认为问题也可能在这里upgradeType = new DefUpgrade(this, level);

this = DefCannon.cs // which inherits from BaseCannon

但是DefUpgrade(BaseCannon baseCannon, int level) DefUpgrade 要求BaseCannon,而不是我们给它一个BaseCannon 的孩子,在这种情况下是DefCannon,这可能是它不起作用的原因吗?我将如何解决这个问题,我没有从子脚本中引用BaseCannon 脚本,有没有办法做到this.BaseCannon,(以某种方式调用父类?)

澄清一下,上面的脚本只用于设置参数,我有一个prefabCannon,没有脚本,当我实例化那个prefabCannon时,我添加脚本DefCannonFireCannon,这取决于我想要哪个cannon实例化,这样我可以让他们都使用他们都需要的通用函数,但每个人都有自定义参数等。

DefUpgrade.cs 这是问题所在,BaseWeapon 脚本中的Debug.Log 有效,但是当它进入DefUpgrade.cs 并尝试调用DoUpgrade() 时,下一步它会失败,因为有Debug.Log在那个脚本中永远不会被调用:

public class DefUpgrade : IDoUpgrade

public int level;
public DefUpgrade(BaseCannon baseCannon, int level)

    this.level = level;
    baseCannon.cost = DefUpgradeDictionary.cost[level];

public void DoUpgrade(BaseCannon baseCannon)

    Debug.Log("Inside DoUpgrade SUCCESS");   // This debug is never reached/called
    var baseDamage = baseCannon.damage / baseCannon.level;
    baseCannon.level++;
    baseCannon.damage = baseDamage * level;
    var lvl = baseCannon.level;
    baseCannon.damageType = new DefDamage(lvl);       //CHECK IF IT WORKS
    baseCannon.minPrecision = DefUpgradeDictionary.minPrecision[lvl];
    baseCannon.maxPrecision = DefUpgradeDictionary.maxPrecision[lvl];
    baseCannon.minReload = DefUpgradeDictionary.minReload[lvl];
    baseCannon.maxReload = DefUpgradeDictionary.maxReload[lvl];
    baseCannon.cost = DefUpgradeDictionary.cost[lvl];



我使用完全相同的界面结构来造成伤害,因为所有大炮都需要造成伤害,但再次使用不同的参数,在那个结构中我没有问题,但是当我为升级重新创建它时,它似乎不起作用但是什么让这变得如此令人困惑的是,没有控制台错误,没有丢失的引用,它调试函数 A,然后调用函数 B,但函数 B 中的调试永远不会被调用!

IDoUpgrade.cs 接口

public interface IDoUpgrade

    void DoUpgrade(BaseCannon cannon);

致电TryDoUpgrade()

baseCannon = PlayerRays.Instance.baseCannon;
    if (PlayerRays.Instance.safe && Island.Instance.gold >= baseCannon.cost)
    
        PlayerRays.Instance.baseWeapon.TryDoUpgrade(baseCannon);
        
    

这最后 2 个脚本工作正常,问题似乎不存在。

感谢您对此进行调查,非常感谢,因为我已经尝试了将近 2 天了。

更新 1:添加 BaseCannon.cs:

public class BaseCannon : BaseWeapon

    private Transform cannon, cylinder, spawn, closestEnemy;
    private MeshRenderer mesh;
    private GameObject flame;
    private List<Transform> enemyShips;
    public Material cannonMat, ballMat;
    public float cbSpeed;
    private float aliveTime = 15f;
    public float minPrecision, maxPrecision, minReload, maxReload;

    void Start()
    
        cannon = transform.Find("Cannon");
        cylinder = cannon.transform.Find("Cylinder");
        spawn = cylinder.transform.Find("Spawn");
        flame = spawn.transform.Find("Flame").gameObject;
        flame.SetActive(false);
        mesh = cannon.GetComponent<MeshRenderer>();
        mesh.material = cannonMat;
    

【问题讨论】:

我猜我们错过了BaseCannon 的代码 ... instead we give it a child of BaseCannon .. 它不是“孩子”,您的 DefCannon BaseCannon 只是带​​有一些额外的字段/方法等.. 除非它 隐藏一个成员(有一个与基类同名但不使用override)应该没有理由让它表现不同 感谢您的快速回复 DerHugo.DefCannon 不隐藏任何内容,仅初始化值,但我按照您的要求添加了 BaseCannon 脚本 :) 我真正需要弄清楚的是为什么 BaseWeapon 中的 upgradeType?.DoUpgrade(cannon); 被调用,但随后从未被执行,也不会在控制台中抛出任何空引用异常。 好吧upgradeType?.DoUpgrade(cannon); 基本上是if(upgradeType != null) upgradeType.DoUpgrade(cannon); 的简写,所以它的全部目的是防止NullReferenceException 但如果upgradeTypenull 则不会做任何事情...你确定DefCannon.Init 被调用了吗? 【参考方案1】:

我认为是 BaseWeapon 类中的错误。 (如果我对结构的理解正确)您传入了 BaseCannon,其中定义了 upgradeType,但您正在从 BaseWeapon 调用该方法。

public class BaseWeapon : MonoBehaviour


public new string name;
public int level = 1;
...
public IDoUpgrade upgradeType;


public void TryDoUpgrade(BaseCannon cannon)

    Debug.Log("Inside TryDoUpgrade SUCCESS");    // This debug works
    upgradeType?.DoUpgrade(cannon);
    
    // in fact the upgrade is null as it's defined in the cannon
    // not the weapon. 
    if (upgradeType == null)
    
        Debug.Log("No upgrade defined. Create from cannon");
        // set the upgrade from the cannon, and then call it
        upgradeType = cannon.upgradeType;
        upgradeType?.DoUpgrade(cannon);
    


【讨论】:

不错的收获!我在上面的评论中和 derhugo 一起解决了这个问题,同时我错过了你的答案,但你是 100% 正确的先生。感谢发帖。 你知道为什么这是有效的吗int dmg = (int)damageType?.DoDamage(target, damage);它从baseweapon调用方法,即使它是由baseCannon定义的,就像DoUpgrade 很难说没有看到该代码,但您没有为 DoDamage 方法传入 BaseCannon,所以我假设它是在大炮预制件本身上调用的。作为对上述其他观点的回答,您始终可以将其转换为“孩子”中的基类。例如。在 BaseCannon BaseWeapon bw = (BaseWeapon)theCannon; ...但它实际上是同一个对象,只是具有您可以通过继承的对象访问的额外方法。因此,如果您在 'child'... 中定义了 DoDamage 到 BaseClass 中,您仍然会调用相同的 DoDamage 方法。

以上是关于unity c# 继承/泛型接口升级不同子类的主要内容,如果未能解决你的问题,请参考以下文章

我在写一个java泛型接口实现时为啥报出double为意外的类型啊?源程序如下!

C# 泛型方法约束为继承自某类时,调用方法,传子类实参,为什么报错?应该怎么写

Java基础-- 继承 多态 泛型 接口 动态绑定 动态代理

JavaSE习题 继承接口和泛型

java--泛型--泛型接口&泛型方法

C#笔记(十四)——接口泛型