Showing member ScriptableObject's in the Inspector

Suppose I have a MonoBehavior which has a public member inherited from ScriptableObject. How can I display the editor for the member object in the same Inspector window that shows the MonoBehavior itself?

What I have

This is the situation in more detail. I have my own asset class inherited from `ScriptableObject’ like this:

public class MyAsset : ScriptableObject {
	
	public int param1 = 1;
	public int param2 = 2;
	public int param3 = 3;

}

I have an instance of MyAsset in the Assets folder, and I can edit it in the Inspector:
13273-screenshot1.png

So far so good. But now I want to use this asset in my MonoBehavior’s. Here is a MonoBehavior descendant:

public class MyBehavior : MonoBehaviour {

	public MyAsset memberAsset;
	
}

Now this is what Inspector looks like when editing a GameObject that has MyBehavior attached to it:

What I want

You see, I can set memberAsset to point to MyAsset instance of my choosing, but if I want to edit the asset itself, I have to do it separately. Is there a way to display an editor for MyAssetInstance below, in the same editor window?

Example that shows it should be possible

As you can see in the same Inspector window, my GameObject has a MeshRenderer component, and that component has in its members a Material. Now the editor for the material appears right below, so you can edit it in place, without losing focus of the GameObject. There must be a way to make MyBehavior-MyAsset pair behave the same as MeshRenderer-Material. My guess is that I want to make a custom Editor for MyBehavior, but I can’t find any methods in EditorGUILayout that would allow me to spawn a new Editor for MyAsset and show it below in the same inspector window. Any help?

Hey, don’t know if you managed to figure this out, but I think CreateEditor or CreateCachedEditor are what you’re after. CreateCachedEditor seemed to be the cleanest and simplest implementation.

So if you have a MonoBehaviour:

using UnityEngine;

public class MyBehaviour : MonoBehaviour
{
    public MyAsset MemberAsset;
    
    // Note: assets don't need to be public for it to work
    [SerializeField] private MyAsset _memberAsset;
}

Where MyAsset derives from ScriptableObject (for example – but any Object should be okay).

You could create something like this (for example):

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(MyBehaviour))]
public class MyBehaviourEditor : Editor
{
    private Editor _editor;
    
    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        
        var myAsset = serializedObject.FindProperty("MemberAsset");
        CreateCachedEditor(myAsset.objectReferenceValue, null, ref _editor);
        _editor.OnInspectorGUI();
        
        serializedObject.ApplyModifiedProperties();
    }
}

(Obviously, you could play with the other functions that can be called on editors here too.)

Note that, it will draw the inspector just as it would if you had it in the inspector. You may not want this (e.g. may not want the script field to display), so you can supply a custom editor that will do the job. In fact, you could write as many editors as you wanted and select which editor will be used as the second parameter (we passed null here, which will just give you the default editor for that Object).

Hope that’s what you were after =).

If anyone’s still wondering and wants a general solution that works for every scriptable object, without needing to write custom inspectors, you can take a look at the post over here: https://forum.unity3d.com/threads/editor-tool-better-scriptableobject-inspector-editing.484393/

It takes a custom property drawer for ScriptableObjects to display every derived class within the main inspector of the MonoBehaviour.

in case someone still looking for a way to do this

One way for such a simple class would be to add getters and setters to MyBehavior that would access the memberAssets properties.

	public int param1
    {
        get
        {
            return memberAsset.param1;
        }
		
		set
		{
			memberAsset.param1 = value;
		}
    }

Mark MyAsset as serializable and it will show up in the inspector nicely.

[System.Serializable]
public class MyAsset : ScriptableObject
{
}