Initializing a parent class and want it to get values from the relevant child.

Hi, I’m creating an RTS and been having a few issues but nothing that google hasn’t solved so far.

In this case, I’m having some trouble with checking the cost of the building I would like to create, and if creating it won’t put the player’s resources below zero. Pretty basic stuff, however it’s not working properly, only when the resources are below zero do I get the correct prompt that the building cannot be created.

Here’s the base class:

public class Building : MonoBehaviour
{
    public int[] cost;
    public GameObject build;
    public int buildingID;
     
    public int lCost { get { return cost[0]; } set { cost[0] = value; } }
    public int sCost { get { return cost[1]; } set { cost[1] = value; } }
    public int mCost { get { return cost[2]; } set { cost[2] = value; } }

    void Start()
    {  
    }
}

Here are the two child classes, each in its own script:

public class House : Building
{
    public int LumberCost;
    public int StoneCost;
    public int MoneyCost;
    
    void Start()
    {
        cost = new int[] { LumberCost, StoneCost, MoneyCost };
        buildingID = 1;
    }    
}

public class TownHall : Building
{
    public int LumberCost;
    public int StoneCost;
    public int MoneyCost;

    void Start()
    {
        cost = new int[] { LumberCost, StoneCost, MoneyCost };
        buildingID = 2;
    }
}

The appropriate script is attached to each prefab along with the Building script.
Now I choose which building to create by using a dropdown list which calls the function in the placement script and sends the correct gameobject to create. Then I create a Building instance from getting the component from the sent gameobject and check if the cost of creating it won’t put the player’s funds below zero, and hold this as a bool which if it’s true, I instantiate the object, otherwise print a message.
Now my problem the way I think of it, is that I’m creating a Building instance instead of House or Town Hall, so the cost values are never really initialized in the Building class, meaning that the values that are checked are null. The reason I’m doing this is that I want it to be more generic rather than checking right away the name of the gameobject and initializing the appropriate class which would probably solve this.

This is the function in my placement script that gets called when the build button is pressed:

 public void setItem(GameObject g)
    {
        Building tempBuilding = g.GetComponent<Building>();

        if ((player.Lumber - tempBuilding.lCost >= 0) && (player.Stone - tempBuilding.sCost >= 0) && (player.Money - tempBuilding.mCost >= 0))
        {
            enoughFunds = true;
        }
        else
        {
            enoughFunds = false;
        }

        if (enoughFunds)
        {
            buildingObject = g;
            isPlaced = false;
            currentBuilding = ((GameObject)Instantiate(g)).transform;
            currentBuilding.gameObject.name = currentBuilding.gameObject.name.Substring(0, currentBuilding.gameObject.name.IndexOf("("));
            buildingType = tempBuilding.name;
        }
        else
        {
            StartCoroutine(ShowMessage("Not enough funds to build this.", 2.0f));
        }      
    }

There’s more stuff in there but keeping it simple since they aren’t really relevant. Then in the update function if currentBuilding isn’t null, then the appropriate things happen. Basically I check the name of the gameobject and initialize the intended child class, subtract the cost from the player’s funds, and place it. There are checks of course for collision, and if the correct mouse button is pressed, but all that works fine.

So I would like some advice about this cause I would really like to avoid initializing the specific child class in setItem(), and instead initialize the parent like I do now in order to have it be more generic, and maybe even avoid initializing the child classes in my update function as well if there’s a way around this.

Thank you.

If you don’t want to create an instance of Building directly then make the class abstract to make sure you never accidentally create an instance of it. Other than that, make the start method virtual in Building and override in any inheriting classes to avoid unexpected behaviour.

Thank you, but the issue here is that I actually want to create an instance of the parent class and want the cost array and buildingID to be populated correctly from just the parent initialization instead of manually having to create an instance of the child class. Cause right now I only have two buildings and that’s only because the project is in the early stages. If I have ten or twenty different building types in the final version, I don’t want to be checking if it’s any of those manually and then initializing the appropriate child class. I have both the Building, and the relevant child class scripts attached to the prefabs, and basically I want by initializing an instance of the Building class to get the correct values from the child class’ initialization without initializing the classes explicitly. I don’t even know if it’s possible, so I’m asking in case anyone has an idea.

Edit:
What I do is basically in update is to get values from the child classes is:

switch (buildingType)
{
     case "House":
     { 
        House placedBuilding = currentBuilding.gameObject.GetComponent<House>();
        ........
        break; }
     case "Town Hall": 
     {
        TownHall placedBuilding = currentBuilding.gameObject.GetComponent<TownHall>();
        ..........
        break; 
}

I would like to avoid this since it would mean I would have to repeat the exact same code for however many types of building I have.

Edit2:
Sorry for the edits, just more things to add.
And the thing is as well, that since the child class instances are created in the switch case, I can’t really use them outside it meaning that it results in a pretty long switch case which I would very much like to avoid.