- Home /
The question is answered, right answer was accepted
Using string to refer to variable
Hi guys,
not sure if my question from the title is correctly formulated. I am working on a 2D Game like Fallout Shelter. I have one script for all my production buildings, no matter of what ressource it is producing. This has worked so far, but as i want to refer to a different script (ressourcemanager) where i add either wood or food, i ended up with 2 code snippets which are very similar, but for the different variable they change in my ressourcemanager.
public void CollectRessources()
{
// FOOD PRODUCTION
if (ressource == "Food")
{
if (ressourceManager.food != ressourceManager.foodLimit)
{
AddGold();
if (ressourceProduced + ressourceManager.food > ressourceManager.foodLimit)
{
ressourceProduced += ressourceManager.food - ressourceManager.foodLimit;
ressourceManager.food = ressourceManager.foodLimit;
ressourceManager.UpdateFood(0);
// Start Production again if Storage was full
if (storageFull)
RestartProduction();
}
else
{
ressourceManager.UpdateFood(ressourceProduced);
ressourceProduced = 0;
collectIcon.SetActive(false);
if (storageFull)
RestartProduction();
}
}
}
// WOOD PRODUCTION
if (ressource == "Wood")
{
if (ressourceManager.wood != ressourceManager.woodLimit)
{
AddGold();
if (ressourceProduced + ressourceManager.wood > ressourceManager.woodLimit)
{
ressourceProduced += ressourceManager.wood - ressourceManager.woodLimit;
ressourceManager.wood = ressourceManager.woodLimit;
ressourceManager.UpdateWood(0);
if (storageFull)
RestartProduction();
}
else
{
ressourceManager.UpdateWood(ressourceProduced);
ressourceProduced = 0;
collectIcon.SetActive(false);
if (storageFull)
RestartProduction();
}
}
}
I am sure there is a better way to solve this, but i did not find anything helpful yet. It would be great if someone can point me in the correct direction. I thought something like this might work, but it doesnt:
public string ressource // this is either "food" or "wood", depending on the building ressourcemanager.[ressource] or something like this..
Answer by ShadyProductions · Jun 11, 2020 at 09:44 AM
Since C# is object oriented, you might aswel make use of that.
You could create a template for your resources, unity has a nice way of creating and visualising data using ScriptableObjects
[CreateAssetMenu(fileName = "Resource", menuName = "Resource")]
public class ResourceConfig : ScriptableObject
{
public string Name;
public int Limit;
}
Create new resource template objects in your folder for each wood, gold etc..
Then assign them somewhere in inspector to your class
// Our actual resource class we will use
public class Resource
{
public string Name;
public int Limit;
public int Amount;
}
// Base class for all your production buildings
public abstract class ProductionBuilding : MonoBehaviour
{
[SerializeField]
private ResourceConfig[] _resources;
public Resource[] CurrentResources { get; private set; }
public virtual void Start()
{
InitializeResources();
}
private void InitializeResources()
{
CurrentResources = new Resource[_resources.Length];
for (int i=0; i < _resources.Length; i++)
{
CurrentResources[i] = new Resource()
{
Name = _resources[i].Name,
Limit = _resources[i].Limit,
Amount = 0,
};
}
}
}
public class Woodcutter : ProductionBuilding
{
// In inspector u can assign wood here as resource for example
public override void Start()
{
base.Start(); // Always call base if you wanna override start method
Print(); // Log all selected resources
}
// Custom logic for this production building
public void Print()
{
foreach (var resource in CurrentResources)
{
Debug.Log("Name: " + resource.Name + " | Amount: " + resource.Amount);
}
}
}
So for example the woodcutter class you would assign to your gameobject in inspector and assign your resource templates. this will be your implementation of the ProductionBuilding class, that class is abstract that means it cannot be put in the inspector. (Intentional)
Each implementation will have CurrentResources which contains an instance of the selected resources.
@SlevinK91 hopefully this gives you an insight on how you could approach this.
Thank you so much for your Answer! I learned so much reading your comment and it surely brings me a step closer to write better code :)
If you got more questions, you're welcome to join this small discord server https://discord.gg/TRASwSQ I am active on it as 'Venomaus' and I'll answer any questions regarding unity.
If this is a bit much, the main idea is the top of the 2nd block "class Resource { name, amount, limit };". That defines a resource as having those 3 parts. Declaring "Resource food=new Resource(), wood=new Resource();" makes variables for food and wood, each with the 3 parts it needs (food.amount is how much food you have). Once you have that, you can do tricks like: "Resource curR; if(type=="food") curR= food;". Or write a function taking a resource: "void changeResourceBy(Resource R, int changeAmt)". changeResource(wood, -3) tries to remove 3 wood.
Yes the comment was a little overwhel$$anonymous$$g at first, but I now have finally grasped the concept of classes (i think) and I started to rework whole lots of my code. Thanks for the nice summary here, that is really helpful to me and the "tricks like" are sth i look forward to implement right now :)
Answer by JavaMcGee · Jun 10, 2020 at 06:39 PM
You might try thinking about it more as general functions and a class for Resource. There's a lot of things you could do, but as a basic example to get from where you are now, you could try something like this:
class Resource {
string name;
int amount;
int limit;
}
And your ResourceManager can have both general types instead of the specific values (you might use a List or Dictionary if there were a lot of resource types):
class ResourceManager { // Don't know what you have here already
Resource wood;
Resource food;
public Resource GetResource(string name) {
if (name == "food") return food;
if (name == "wood") return wood;
}
...
Then, instead of your above two duplicate snippets, you'd call a function:
AddResource(resourceManage.GetResource("food"));
AddResource(resourceManage.GetResource("wood"));
void AddResource(Resource resource) {
if (resource.amount != ressource.limit)
{
AddGold();
if (ressourceProduced + ressource.amount > ressource.limit)
{ .... you fill in the rest
}
Thanks a lot for the answer! It seems to me though, that i will have to read more about global classes in order to get everything going there. I was able to use the parts you provided, but now i can not find out how to set the variables i defined in the new Ressource class.. Thanks anyway for your help here :)