I’m currently building an ability system for my game and I decided to re-do most of the mecahnics with ScriptableObjects instead of classes. While it does seem to make the Inspector clear and easier to sort through abilities, I don’t understand how ScriptableObjects retain unique data when multiple GameObjects are using it.
For example, lets say I have a TrainingBot prefab that shoots a projectile every second. The data for projectile type, firingDelay, damage, etc is stored on a ScriptableObject (lets call it “TrainingBotProjectile”)
During gameplay, I instantiate 3 TrainingBot prefabs who at first have identical rate of fire. However, during gameplay if I hit one of the bots, the SO has code to increase their firing delay. Since all 3 bots are using the same SO for their data, does this mean every bot will have an increased firing delay now?
Does each GameObject/prefab make a copy of the original SO and modify the copy’s data? If so, then it would probably work fine. I’ve tried simulating the above scenario by modifying and printing statements and it seems that each prefab makes a copy of the SO, and modifies that rather than the original. Even so, I still feel like they will conflict with each other further down the road. Another example would be if a SO stored a list of targets, I wouldn’t want EVERY gameobject using that mechanic to target the same entity.
Would I solve this problem by instantiating a SO during gameplay? I’ve read the documentation and some forum posts but I haven’t found a clear answer on what instantiating actually does, since it doesn’t create a SO in the scene.
That is exactly how I would do it. In fact, if I had a public slot in my bot for his ScriptableObject data:
public TrainingBotProjectile projectile;
then in my TrainingBot’s Start() method I would:
void Start()
{
// make a runtime copy; This will have all public fields from the
// original but it does not exist on disk. However, it CAN
// still be double-clicked on in the inspector and modified.
projectile = Instantiate<TrainingBotProjectile>( projectile);
// from now on all changes you make to projectile will be this
// runtime clone, which will disappear when you press STOP
}
To clarify: The TrainingBotProjectile example is a ScriptableObject correct?
Also, what is the difference between Instantiate and CreateInstance()? The documentation on CreateInstance doesn’t have much of an explanation on what it does.
Ah okay so I guess Instantiate is the way to go then.
Does Unity automatically delete instantiated SO when the GameObject that created them is gone. I wouldn’t want a bunch of SO floating around in memory from constantly spawning & destroying something like a Training Bot.
I also assume Instantiating a SO doesn’t mean any SO nested inside it are also duplicated. If SO1 has a public variable SO2 and I duplicate SO1, then SO1 and SO1(Duplicated) are both still pointing to the same SO2.
They become eligible for removal when nothing refers to them, just like everything else in the C# / Unity engine ecosystem.
Also, GameObjects don’t have any code. They don’t create anything. They can host script instances such as MonoBehaviours. But there is no connection between a ScriptableObject and a MonoBehaviour, unless the MB has a reference to it, and even then it’s just a one-way reference like any other C# reference.
ALSO, like any UnityObject, you can never use the new keyword to make MonoBehaviours or ScriptableObjects.
Oh sorry I said GameObject when I was referring to a script on the object (AbilityManager.cs). When the gameobject is deleted, so is it’s AbilityManager script, and at that point there shouldn’t be any script/variable still pointing to the instantiated ScriptableObject, and it will be deleted.
I’ll need to rummage through my code a bit, but I think I can get So to work for my game. Thank you for the help, I really appreciate it!