I am currently working on a small side project (as usual), and trying to build up from previous experiences.
I have the following elements in the game:
1) Region
: which contain a "food" target that has to be met
2) Location
: Each region has a few location, where crops can be sown
3) Crop
: A variety of crops with different effects
I currently have a system where I have a Region monobehaviour script that only considers the production of food from the crops. The location monobehaviour, stores the current state of the location, namely what crop is currently on it and how much food is currently available. I also have all the food production logic on that script. The crop scripts are scriptable objects with different food production rates and water consumption values.
I run into a problem when I started to want to add other types of elements to the location, or rather, have crops that don't necessarily produce food but have another effect on the game.
I decided to build another system, where instead of having the logic that triggers the various methods on the location script (for example the ProduceFood()
, SendFood()
, ReceiveFood()
) within the location script itself or via hard links from UI elements.
This new systems is centred on Action
scriptableObjects that can be added to the Crop
scriptableobjects. The action script contains an Act(Location loc)
method as well as a SetUp(Location loc)
and Disable(Location loc). I can now customise how and when the ProduceFood()
, SendFood()
, ReceiveFood()
, etc methods on the location script get called. For example the ProduceAction
will add the Act
method to a delegate event on the location script that triggers when a global OnProduction
event gets triggered. Similarly, my hard UI links now point to a method on the location script called UITriggerAction(int index)
which triggers the Act method registered to a delegate array on the location script.
Now each time a change the crop at a location I call the Disable method on all the Actions of the current crop, then I replace the crop and call the SetUp
method on it, which will either register the associated Act method to the array accessible from UI, or to some other custom event.
The Act
methods would be simple and look like:
Act(Location loc)
{
loc.Produce();
}
or
Act(Location loc)
{
if(loc.HasProduced())
{
loc.SendFood();
}
}
By doing it this way I keep the variables specific to the location on the location script as well as the logic on it. In addition I avoid any dependency between the current crop at a location and the rest of the game. For example I could have a method from the Region
script, that would check all the currentFood
values on the locations, and it would still work even if the crop at that location doesn't impact the currentFood
value at that location.
int AvailableFood()
{
int availableFood = 0;
for (i = 0; i < loactions.Length; i++)
{
availableFood += loactions[i].currentFood;
}
return availableFood;
}
I just control the way in which I call those methods using a more versatile system.
My question is: Is this likely to lead to a very messy code on the location script where I will have all the variables and all the methods to do everything?
Do you have any suggestions on how I can improve that system?
Supporting code:
class Location : MonoBehaviour
{
Region parentRegion;
Crop currentCrop;
public int currentFood;
int maxFood;
public delegate CropAction(Location loc);
public CropAction[] actions = new CropAction[6] // 6 possible actions accessible from UI
public void UITriggerAction(int index) { actions[index](this); }
public void Produce() { // Do stuff }
public void SendFood() { // Do stuff }
public void RecieveFood() { // Do stuff }
public void UseWater() { // Do stuff }
public bool HasProduced() { return currentFood > 0; }
public AddCrop(Crop crop)
{
loc.Produce();
}
}