# Can't use one variable to store different data types. What's a better solution?

I'm trying to make my first game in Unity and I decided to have a go at making a 3D tower defence. I've created a UI Panel with 4 buttons used to upgrade the turrets. When the player selects a turret the panel appears and the button text and images are changed to match the type of turret selected. The buttons all call one function 'UpgradeButtonClick(int upgradeIndex)' which applies the upgrade to the selected turret.

In order to reuse a single panel and one set of buttons I created a class called 'Turret' which will be attached to every type of turret. This class stores the cost, materials and upgrades for the turret as well as a reference to the attack script for the turret. This was fine until I introduced a second type of turret (I.e. lazer turrets and fire turrets). Originally I had:

public LazerTurretShooting attackScript;


But that will obviously not work for the fire turret. Ideally I would like to test the type of turret and then declare the correct variable type. But I can't as the variable would then only be accessible where it is declared and not to the whole class.

The attackScript variable is used near the bottom of the UpgradeButtonClick function to modify the turrets damageMultiplier and apply the upgradeEffect. See below:

public class TurretManager : MonoBehaviour {

/* Removed unnecessary functions */

{

Turret turret = selectedTurret.GetComponentInParent<Turret>(); //Get the Turret script from the selected turret

{

{
int prerequisiteIndex;

//Check if the upgrade requires a previous upgrade to be applied first
if (prerequisiteIndex > -1)
{

} else
}

} else
{ //There was no prerequisite so allow the upgrade
}

{
{
UpdateUpgradePanelButtons(); //Update the buttons to enable buttons for any upgrades which require this upgrade as a prerequisite

{
}

}

}

}

}

}

}


Here is the full Turret class:

[System.Serializable]
{
[Tooltip ("The damage multiplier is increased additively. So to increase damage by 20% enter 0.2 or to decrease enter -0.2")]
public float damageMultiplier;
[Tooltip("Tells the turret to play its additional effect (E.g. Dual Lazers on a lazer turret)")]
[Tooltip ("Index of upgrade required before this upgrade can be applied. (-1 = none required)")]
[HideInInspector]
public bool applied; //Has the upgrade been applied to this turret
[Tooltip ("Text to display under the upgrade button (E.g. '10% Damage Increase')")]
[Tooltip ("The cost of the upgrade")]
[Tooltip ("A Sprite image for the upgrade button")]
public Sprite buttonSprite;

}

public class Turret : MonoBehaviour {
public Material opaqueMaterial;
public Material translucentMaterial;
public int cost;
public LazerTurretShooting attackScript; //This variable would need to store different types

void Awake()
{
//I need to get the correct type of script for this turret
attackScript = GetComponent<LazerTurretShooting>();
//attackScript = GetComponent<FireTurretShooting>();
//attackScript = GetComponent<etc>();
}
}


What would be the best way to approach this? If I create separate 'Turret' classes (E.g. LazerTurret and FireTurret) the function which sets the text and images of the upgrade buttons wouldn't work because it usees:

Turret turret = selectedTurret.GetComponentInParent<Turret>();
for (...) //Loops all 4 buttons
//etc


I can provide this full function if its needed.

Like @PompeyPaul says, Polymorphism is key. To expand on the idea, here is another possible design for a Turret class:

public abstract class Turret : Monobehavior {
...
public abstract void Attack();
}


Assuming that everything besides how the turrets attack and are upgraded is the same for every type, this would expose a common interface for all turrets. Now you could make different specific turret classes:

public class LaserTurret : Turret {
public int statSpecificToLasers = 5;
public void Attack() {
//do something cool with a laser
}
//Apply changes to statSpecificToLasers
}
}

public class FireTurret : Turret {
public int statSpecificToFire = 12;
public void Attack() {
//do something cool with fire
}
//Apply changes to statSpecificToFire
}
}


Because the Turret class has virtual methods, you can't really have a concrete Turret, so it cannot be constructed, and you wouldn't attach it to any GamEObjects, but since both LaserTurret and FireTurret inherit from Turret, both can be treated as if they were Turrets. Now, in your TurretManager, selectedTurret can still be declared as a Turret type, but you can pass in either a FireTurret or a LaserTurret. Which Attack() or Upgrade() method gets called depends on which type you pass.

Turret selectedTurret = ob1.GetComponent<FireTurret>();
selectedTurret.Attack(); //shoots fire
selectedTurret = ob2.GetComponent<LaserTurret>();
selectedTurret.Attack(); //shoots a laser

//You can even put them in the same collection
List<Turret> turrets = new List<Turret>();

• Thank you for the detailed answer. I ended up creating 'public bool applyUpgradeEffect' and 'public abstract float damageMultiplier' in the Turret class. I then made an override for the damageMultiplier in my LazerTurret class which means I can now reference any turret with 'GetComponent<Turret>()' and then use turret.damageMultiplier. So there is no need for the attackScript variable any more even though damageMultiplier is implemented in the 'LazerTurret' child class. It's made it much easier to use and to implement new turrets, thank you. – Daniel Oct 13 '16 at 21:09
• @Daniel, After your comment, I realized I got my languages a bit mixed up and should have used "abstract" instead of "virtual." I updated my answer accordingly, but it is good to hear it works. – tyjkenn Oct 14 '16 at 14:59

It sounds like you need polymorphism in your class design. I would start with a base turret, as you have, which has all of the base functionality. It also has virtual functions for accessing parts of it.

You then have an TurretAttackBase script which has the common attack base functionality. You then derive cannon attack, laser attack, etc from that.

You then create a turret prefab which has the type of turret, and attach the TurretAttackLaser or whatever to it.

Your script then calls the virtual functions to get the TurretAttack and calls request upgrade.

That way you have one consistent interface but with different derived turrets, attack types etc all handling correctly.

So for your turrent you would call

turret.attackScript.ApplyUpgradeEffect();


The turret would then get the attack script, call ApplyUpgradeEffect() and it will be called on either the TurretAttackLaser or TurretAttackCannon class depending on which type it actually is.

• Thank you very much for your answer. Although your answer was very useful I chose to accept tyjkenn's answer as the examples made it easier to implement. – Daniel Oct 13 '16 at 21:13