- Home /
How to reference MonoBehaviour in ScriptableObject?
Hi everybody,
I'm making a ScriptableObject asset type to facilitate quest development. The ScriptableObject will store quest metadata as well as a link to a MonoBehaviour extending type that defines the quest logic.
However, when I inspect the quest asset, while a MonoBehaviour field shows up, I cannot reference any of the MonoBehaviour scripts with it.
So, does anybody know how to add a MonoBehaviour reference to a ScriptableObject that can be assigned in the inspector?
Also see https://answers.unity.com/questions/1036336/serialize-a-reference-to-monobehaviour-type-in-scr.html where I also commented and added a link to a repo allowing this
Answer by Bunny83 · Jul 29, 2012 at 11:15 PM
You have a fundamental logic mistake here ;) A ScriptableObject-Asset is an asset. Assets are just objects which are available at any time to your runtime. You can instantiate them when you need one.
Those assets can't directly reference objects that only exists in a scene, since the objects in a scene are only available when the scene is loaded. So basically assets can reference assets and scene objects can reference scene objects(from the same scene of course) and assets.
You might want to use a singleton pattern instead. Another way is to link up your objects manually at start (GameObject.Find & GetComponent, FindObjectsOfType).
edit
Well, the only way to add a MonoBehaviour Component, which tyoe is not known at compile time, at runtime would be to use the System.Type object of that class or the string version. However Unity's default inspector only allows drag and drop with objects that are derived from UnityEngine.Object. Also i think Unity can't serialize a System.Type variable.
So the best bet is to store the type name as string and use AddComponent with the type name instead of a Type-object.
The downside is of course that you only get a Component reference back. If you know the type you can cast it to the correct type, but that complicates the interaction with the component unless your components are all derived from a common interface.
$$anonymous$$aybe I should have explained a bit more context. The quests are auto-generated uScript $$anonymous$$onoBehaviours that are hooked up to their dependent components / gameobjects at runtime (i.e., when you acquire the quest.)
I don't want the ScriptableObject to reference an existing monobehaviour in the scene; that's not possible. I want it to reference a $$anonymous$$onoBehaviour type that I can choose in the editor (Quest asset insepctor) so that when the quest is acquired, the logic associated with the quest can be instantiated as a $$anonymous$$onoBehaviour (the uScript auto-generated type).
Ahh ok, the question is a bit misleadig ;)
I'll edit my answer...
Ahhh...okay, I was afraid of that. The system will only accept one type, so type safety isn't a terribblyyy large issue, but the problem is that non-programmers are going to be the ones developing the quests, so I was hoping to reduce the number of steps as much as possible.
Is there any way to overcome this limitation by implementing a custom editor?
Thank you for your time regardless!
Hey just a side note, you can drag and drop the scripts into fields of '$$anonymous$$onoScript'.
$$anonymous$$onoscript itself is an Editor Class, but you can treat it like a TextAsset at Runtime. You can use this to get the name of your scripts, and use this name to add components. I have not done this myself, but I think you could probably find a use for it. At the very least, it makes handling the strings easier, since rena$$anonymous$$g a script file would rename the reference that the object has. Not sure what the effects will be in terms of efficiency/memory, but maybe this will help. Good Luck, Have Fun.
@Avaista: Yes this does work, i've done this already in an editor script ;) $$anonymous$$onoScript has some useful functions, but the mostimportant is GetType which returns the System.Type object for the class that is contained in the script.
Do you necessarily need to use a ScriptableObject? You can also create an custom editor which creates prefabs according to your data. I've made an item importer which creates prefabs for equipable weapons / armor from a simple text file. The textfile was created by our gamedesigner. It specifies all stats of the weapons, which model / modelpart and which texture the item is using and finally what gui texture it has. The importer creates seperate prefabs for each specified item and even add it to a list on an item manager prefab. Worked pretty well ;)
Answer by Archimagus · Mar 30, 2015 at 05:47 AM
I think I may have found what you are looking for. It's not pretty but it will let you pick a script. In your scriptable object, questData have a string to represent the monobehaviour.
Then add a custom editor for it, here is the code to select a monobehaviour script.
MonoScript script = null;
if (questData.functionality!= null)
{
string guid = AssetDatabase.FindAssets(questData.functionality).FirstOrDefault();
if (!string.IsNullOrEmpty(guid))
script = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), typeof(MonoScript)) as MonoScript;
}
script = (EditorGUILayout.ObjectField(new GUIContent("Quest Functionality: "), script, typeof(MonoScript), false) as MonoScript);
if (script != null)
questData.functionality = script.GetClass().FullName;
then, to instantiate it
Type t = Type.GetType(questData.functionality);
if (t != null)
{
gameObject.AddComponent(t);
}
Your answer
Follow this Question
Related Questions
How should I serialize data that is also editable in the Inspector? 2 Answers
Scriptable Object only useable from code, not via inspector 1 Answer
Custom Editor Window not displaying anything 1 Answer
Using ScriptableObjects to build ECS archetypes 0 Answers
[Solved]Why doesn't my ScriptableObject based asset save using a custom inspector ? 1 Answer