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时,我添加脚本DefCannon
或FireCannon
,这取决于我想要哪个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
但如果upgradeType
是null
则不会做任何事情...你确定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# 泛型方法约束为继承自某类时,调用方法,传子类实参,为什么报错?应该怎么写