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?
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.
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.
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);
}