I am trying to create an extensible utility that generates objects based on some data. I’d like to be able to generate these objects based on a selected script that can be assigned to a field in the inspector (on a gameobject or in an editor window).
I might for example have the classes “Generator”, “ObjectGenerator : Generator”, “ImageGenerator : Generator”, “VectorGenerator : Generator”. Any developer can add whatever generator classes they like, they just need to be able to assign them to a field, which will be read and used by some executing code.
So far I haven’t seen any way to do this, other than doing annoying things like adding these scripts as components on to otherwise useless objects in the hierarchy. I’d really rather not hard code the available options and display them all as a list. I also need to be able to assign this field from code.
I don’t need the above system exactly, just some way that works similarly without a difficult process for the end user. Ideally there would also be a way for them to control the parameters and variables on their selected script, like a regular inspector.
I think the use of ScriptableObject might be handy to you here. It’s a bit long, but if you look at the tutorial series “Pluggable AI With Scriptable Objects”, it might help. The thing I was Googling to figure out when I found this thread was “why do I need to make classes and then make assets and then assign those assets?” I think the answer is that you simply can’t assign classes that way, but using ScriptableObject classes, generating a single asset for that SO, and then assigning it in the inspector works. I hope this at least helps!
There is a way to skip the whole “assign the SO manually” step. The variable type you need is Monoscript.
public MonoScript script;
public List<ScriptableObject> testList = new List<ScriptableObject>();
The attribute you see above is an Odin Inspector attribute, which is a plugin available in the asset store, but you could also have your own mechanism for doing the same thing, which is calling a function whenever the value of our script variable changes. I’ll get to the list part in a second. Let’s look at the ReadScript function first.
The function looks like this:
private void ReadScript ()
var assetType = script.GetClass();
var instance = ScriptableObject.CreateInstance(assetType);
In a nutshell what we’re doing here is getting the type defined in the script file each time the user assigns a new script to the script variable, and creating a new instance of that type. I am also checking to make sure the type inherits from ScriptableObject, which has a couple advantages, like being able to save the newly created instance as an asset and being able to modify it with an inline editor (again, courtesy of Odin). After creating the new instance I’m saving it with the AssetDatabase (which makes the data on it persist) and I add it to a list which has the [InlineEditor] attribute, which is the thing that allows you to edit its fields in the editor.
The flaw in this example is that each time you create a new instance of something, it will overwrite the NewInstance.asset file, since we’re not checking to see if the file name exists in the first place. You can add your own mechanism of making sure file names stay unique.
Hope this helps.