Hello,
I would like to know if it’s better to create a ScriptableObject instance at runtime (editor-only, to prevent modifications to default values) or create a class using the ScriptableObject values. Example: suppose I have the UpgradeSO as shown below.
public class UpgradeSO : ScriptableObject
{
public string title = "New Upgrade";
public int level = 0;
public PreRequisiteUpgrade[] upgradeRequisites;
}
[System.Serializable] public struct PreRequisiteUpgrade
{
public int minLevelNeeded;
public UpgradeSO upgradeNeeded;
}
So, I want to be able to display the upgrade on the upgrade store as long as all pre-requisites are met. Example: upgradeA has, in it’s upgradeRequisites[0], minLevelNeed = 5 and upgradeNeeded = upgradeB (set in the inspector). So upgradeA should only be displayed on the store as long as upgradeB is at level 5 or more. So far so good.
In my GameManager script I have an array of upgrades (UpgradeSO[ ] upgrades) that loads from all UpgradeSO in the Resources folder. The problem is: if I make a change to any value of upgradeA (ex: level = 2), it modifies the actual asset on the Resources folder, so if I re-enter play mode it will begin at level 2.
The solution I found is to instantiate every UpgradeSO on the Awake() function of GameManager, for editor only. But the problem is: I have to instantiate every UpgradeSO in the upgrades array and then, for each upgrade, loop through its upgradeRequisites, find the UpgradeSO (instance) in the upgrades array for which the title corresponds to upgradeNeeded.title and assign it to upgradeRequisites.upgradeNeeded, because of I don’t do this, upgradeNeeded will continue referencing the actual asset on Resources folder. This is presented below:
private void Awake()
{
for (int i = 0; i < upgrades.Length; i++)
upgrades[i] = Instantiate(upgrades[i]);
for (int i = 0; i < upgrades.Length; i++)
for (int j = 0; j < upgrades[i].upgradeRequisites.Length; j++)
upgrades[i].upgradeRequisites[j].upgrade = Array.Find(upgrades, element => element.title == upgrades[i].upgradeRequisites[j].upgrade.title);
}
Also, I will have later other fields that contain references to ScriptableObjects, so I would need to instantiate them all first and loop again etc.
I also thought of creating an Upgrade Class that has a constructor that takes an UpgradeSO as argument and gets all the data from that UpgradeSO. This way, I could create objects of that class from the UpgradeSO in the Resource folder, and use it as I would use the ScriptableObject without modifying the assets.
What should I do to solve this problem? I’m kinda lost of what is better here (both to organize better and to have better performance) and would like any help.
Thanks!