advice on resource management system architecture
hi so i got resources like wood stone food,each can be produced by multiple sources. each source will have different amount and rate of harvest. I will be harvesting with mouse click. I am confused how to go about and set things up.
First i have a resource script like this
// class to define resources
// attached to every object which can produce resource
public class Resource: MonoBehaviour
{
public enum ResourceTypes
{
Wood,
Stone,
Food,
};
public ResourceTypes resourceType;
public float gatherableAmount;
public float gatherPerSec;
public GameObject resourceImage;
public AudioClip ResourceGatheringSfx;
}
and add this as a component to each of the sources and select the resource type then with my input class that handles raycast i will have to compare hit.resourceType with a string of the resource type which to me feels bad cuz of alot of if statements.
public class ResourceInput : MonoBehaviour
{
Resource res;
void Update ()
{
if (Input.GetMouseButton (0))
{
Vector3 mousePos = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 10f);
Ray ray = Camera.main.ScreenPointToRay (mousePos);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, 100f))
{
if (hit.collider.tag == hit.transform.GetComponent<Resource> ().resourceType.ToString ())
{
res = hit.transform.GetComponent<Resource> ();
if (res.gatherableAmount > 0)
{
res.gatherableAmount -= res.gatherPerSec * Time.deltaTime;
ResourceManager.Instance.AddResource (res.resourceType, res.gatherPerSec * Time.deltaTime);
}
else
{
hit.transform.gameObject.SetActive (false);
}
}
}
}
}
}
the problem arises in this script with all the if statements especially when i add more resources
// class to manage resources collected
public class ResourceManager : Singleton<ResourceManager>
{
public float woodCollected;
public float stoneCollected;
public float foodCollected;
public void AddResource (Resource.ResourceTypes resType, float amount)
{
if (resType.ToString () == "Wood") {
woodCollected += amount;
}
if (resType.ToString () == "Stone") {
stoneCollected += amount;
}
if (resType.ToString () == "Food") {
foodCollected += amount;
}
}
}
can someone suggest me a good structure in which i do not have to do these if statements?
Answer by KittenSnipes · Jan 29, 2018 at 11:02 AM
I think I would make a separate class to define the type of resource then I would make a class that holds all the resources. I would make my resource class hold the string of the name, and a gameObject of the object. I would define whatever my resource is in that class and then hold how much of it in the other. Thats about it. Something like:
Resource.AddResource(ResourceType.Wood, 10);
hmm i dont get how thats different than my first approach. I will still have to use if statements in my harvesting class using raycast to see which resource to add. i am trying to avoid that. what i want is that i should be able to click and call a method Harvest and i should harvest without this class knowing what to harvest
I’ll make sure to make some example scripts to show you how it is different when I am at my computer so until then cheers mate
hey @$$anonymous$$ittenSnipes I have tried to follow your suggestion and updated the question but the problem remains the same. Can you clarify what should be done?
Answer by Nighfox · Jan 30, 2018 at 02:06 PM
Not a really elegant solution, but if you want a quick one to use enums and in the same time serialize your members easily, you can do something like this. All you need to do is to assign types yourself (either in the inspector or some Init method):
using System.Collections.Generic;
using UnityEngine;
public enum ResourceType { Wood, Stone, Food };
public class ResourceManager : MonoBehaviour {
//list of resource types, should only have unique types
public List<ResourceData> resources = new List<ResourceData>();
public void AddResource(ResourceType resourceType, float amount)
{
//loop through types of resources
foreach (ResourceData res in resources)
{
//match found
if (res.resourceType == resourceType)
//add amount to res data
res.amount += amount;
}
}
}
[System.Serializable]
public class ResourceData
{
//you can add a definition var here, which will contain defining data (name, desc, etc)
public ResourceType resourceType;
public float amount;
}
Now you can add as many types as you want without worrying to create an if statement for each resource type.
Thanks for replying with a approach using enums ,this is definitely better than my approach. it broadens my understanding thanks.
Your answer
Follow this Question
Related Questions
Need a parent class that holds a method that use (or not) a parameter 1 Answer
Child class cannot access property in method? 1 Answer
How to make RequireComponent list possible options. 1 Answer
Generic RPG Ability-System structure 0 Answers
Strange behaviour when inheriting parent class with Monobehaviour 1 Answer