Home > Software engineering >  Unity c# Inheritance / generic Interface to upgrade different subclasses
Unity c# Inheritance / generic Interface to upgrade different subclasses

Time:12-15

I am trying to upgrade a specific cannon, by using an interface, the problem I am facing is that for some reason the functions are being called correctly and there are no errors, but in fact the parameteres are not "upgraded" as expected.

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);
}

The above debug works, and gold is subtracted from the player as expected.

DefCannon.cs I use this to instantiate a BaseCannon that inherits from BaseWeapon, with custom parameters, this is the default cannon, I also have a FireCannon as an example, they all inherit from BaseCannon, which in turn inherits from 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);
}
}

I think the problem might be here aswell upgradeType = new DefUpgrade(this, level);

this = DefCannon.cs // which inherits from BaseCannon

However DefUpgrade(BaseCannon baseCannon, int level) DefUpgrade is asking for a BaseCannon, instead we give it a child of BaseCannon in this case that is DefCannon, might this be the reason why its not working? and how would I solve this, I dont have a reference to the BaseCannon script from the child script, is there a way to do this.BaseCannon, (calling the parent class somehow?)

To clarify, the above script is only used to set the parameters, I have a prefabCannon, with no scripts, when I instatiate that prefabCannon, I add the script DefCannon or FireCannon, depending on which cannon I want to Instantiate, this way I can have them all use the generic functions they would all need, but have custom paramters and such for each one as well.

DefUpgrade.cs This is were the problem is, the Debug.Log in the BaseWeapon script works, but the next step it takes when it enters into DefUpgrade.cs and tries to call DoUpgrade() fails, because there Debug.Log in that script is never called:

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];

}
}

I used the exact same interface structure to do damage, as all cannons need to do damage, but again with different params, in that structure I have no issues, but as I recreated it for Upgrades it doesnt seem to work but what makes this so confusing is that there are no console errors, no missing references, it debugs function A that then calls function B, but the debug in function B then never gets called!

IDoUpgrade.cs interface

public interface IDoUpgrade
{
    void DoUpgrade(BaseCannon cannon);
}

Calling TryDoUpgrade()

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

These last 2 scripts work fine, the problem doesnt seem to be there.

Thank you for looking into this I appreciate it a lot as ive been trying to figure this out for almost 2 days now.

Update1: Added 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;
    }
}

CodePudding user response:

The error I believe is in the BaseWeapon class. (If I understand the structure correctly) You're passing in the BaseCannon which has the upgradeType defined in it, but you're calling the method from the 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);
    }
}
}
  • Related