- Home /
efficient way to make RTS building instances
I am working on a construction system for my RTS. Each building requires different amounts of cordage, wood, stone etc. My first attempt was to make a class "structure" and then make a child class for each building type which would specify its building requirements and other stats such as hit points.
The problem with this approach is that it requires a long if statement to work. For example, I press the 'build' button and the worker finds the closest construction site and takes materials to it. In order for the worker to know what materials to bring and how much, they must access the component unique to that structure. Since every structure type has a different class, I need to create an if statement like in the following pseudo code:
if (closestConstructionSite.name == "Wood Storage")
{
woodStorageScript = closestConstructionSite.transform.GetComponent<WoodStorage>();
}
else if(closestConstructionSite.name == "Stone Wall")
{
stoneWallScript = closestConstructionSite.transform.GetComponent<StoneWall>();
}
//etc.... for every building type that I have.
I'm more than happy to do this but I've got a sinking feeling that there is a better way. Any ideas?
Answer by Kiwasi · Dec 06, 2014 at 12:29 AM
Some pseudo code may illustrate the point.
public class Structure : MonoBehaviour {
public string structureName;
public int structureID;
public int structureHP;
public int requiredWood;
public int requiredCordage;
...
}
public class TreeHouse : Structure {
void Start (){
requiredWood = 30;
}
}
public class Builder : MonoBehavour{
void SomeFunction (){
woodRemaining = constructionSite.GetComponent(typeof(Structure)).requiredWood;
}
}
ahhh, I've never seen the typeof(x) syntax before. I'm going to try it out right away. I think that was the missing link for me. Thanks a lot skaredcreations and bored$$anonymous$$ormon for your help.
ok... really sorry to be slow but I need to be sure. I've attached a woodStorage script to the wood storage prefab. It inherits from the structure script. $$anonymous$$y worker finds the closest construction site and needs to access the woodStorage component. I tried to do this by doing the following code:
public void FindClosestBuilding()
{
pathFindingScript.can$$anonymous$$ove= true;
closestEmptyBuilding = hugeVector;
for(int i = 0; i < managerScript.emptyBuildings.Count; i++)
{
if(Vector3.Distance (transform.position, managerScript.emptyBuildings[i].transform.position) < Vector3.Distance(transform.position, closestEmptyBuilding))
{
closestEmptyBuilding = managerScript.emptyBuildings[i].transform.position;
emptyBuilding = managerScript.emptyBuildings[i];
}
}
if(emptyBuilding != null)
{
pathFindingScript.target = emptyBuilding.transform.position;
pathFindingScript.findTarget = true;
interactionScript.transportingState = Interaction.TransportingStates.Deposit$$anonymous$$aterials;
}
}
//in the next state, this method is evertually called:
public void Add$$anonymous$$aterialsToBuildingSite()
{
if(emptyBuilding.GetComponent(typeof(Structure)).requiredWood != 0)
{
//add wood
}
}
The problem is that emptyBuilding.GetComponent(typeof(Structure)).x is not accessing any values. What have I missed? Thanks again for your time.
ah man, I'm spam$$anonymous$$g! well it seems to work when I just do GetComponent().requiredWood, but I'd like to know why the typeof thing didn't work out. This formatting looks interesting.
Answer by SkaredCreations · Dec 04, 2014 at 02:08 AM
Why not adding the requirements (materials, hit points etc) directly in the base building class? Since every building has requirements I see no reason to add this in every subclass, I did this way in the last RTS having HitPoints, RequireWood, RequireIron etc as "int" type in the BaseBuilding class. The buildings that don't require a specific resource would have the property set to 0.
Polymorphism is the answer. One alternative to endless derived classes is to have the constructionSite own an instance of costData. Either as a reference in your script, or a a seperate component.
Thanks for the replies! Ideally I would have just one base building class. This would make accessing the component and finding out the number of materials etc. much easier. $$anonymous$$y problem is that I do not know how to do this with one script. How would I use polymorphism to solve this problem? I've attached my base building class just so you can see what I'm up to:
public class Structure
{
public string structureName;
public int structureID;
public int structureHP;
public int requiredWood;
public int requiredCordage;
public int required$$anonymous$$ud;
public int requiredStraw;
public int requiredStones;
public int currentWood;
public int currentCordage;
public int current$$anonymous$$ud;
public int currentStraw;
public int currentStones;
public int structureCurrentHP;
public float buildTime; //this is how long the building would take to construct if the person was a master of their craft.
public Vector3 structureLocation;
public bool structureBuilt;
public Structure()
{
}
public Structure(float time, string name, int id, int hp, int wood, int cordage, int mud, int straw, int stones, int cwood, int ccordage, int cmud, int cstraw, int cstones, int currentHP)
{
buildTime = time;
structureName = name;
structureID = id;
structureHP = hp;
requiredWood = wood;
requiredCordage = cordage;
required$$anonymous$$ud = mud;
requiredStraw = straw;
requiredStones = stones;
currentWood = cwood;
currentCordage = ccordage;
current$$anonymous$$ud = cmud;
currentStraw = cstraw;
currentStones = cstones;
structureCurrentHP = currentHP;
}
}
Your issue is easily solved by setting the values of properties in the constructor of the subclasses. In my case I inherited the BaseBuilding (your Structure) from $$anonymous$$onobehavior so I could attach the script directly to the prefab. Why you created a class ins$$anonymous$$d of a component? Your StoneWall should ideally inherit from Structure and Structure should inherit from $$anonymous$$onobehavior, this way it's very easy to access its properties from the Worker script in your first post by using GetComponent() ins$$anonymous$$d of the long "if else" statement.
Your answer
Follow this Question
Related Questions
C# Inheritance, base class attributes, override and null object 1 Answer
inheritance - instance variable problem? 4 Answers
Is Instance Of 3 Answers
Change a Class in the inspector 1 Answer
RTS building snap to grid 2 Answers