- Home /
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:
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?
@BigRoy It was a long time ago. As far as I remember, I wasn't able to reproduce the behavior of $$anonymous$$eshRenderer-$$anonymous$$aterial
pair exactly.
Answer by Johat · Aug 20, 2015 at 07:39 PM
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 =).
I searched for hours trying to find the answer to this, it was exactly what I was after.
Answer by TheVastBernie · Jul 22, 2017 at 04:27 PM
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.
This was simple and helped me. Thank you for referring to that thread!
Answer by as3mbus · Nov 15, 2019 at 10:24 AM
https://gist.github.com/tomkail/ba4136e6aa990f4dc94e0d39ec6a058c
in case someone still looking for a way to do this
Answer by hatuf · Jul 19, 2013 at 08:24 AM
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;
}
}
This is an interestind idea, but I have a feeling that if $$anonymous$$yAsset grows more complex, this can quickly get out of hand. Also, it's not clear how to adjust the approach if ins$$anonymous$$d of a single $$anonymous$$yAsset
$$anonymous$$yBehavior
contained, say, a List
of them with unknown length.
Answer by JohnnySunshine · Jul 19, 2013 at 09:55 AM
Mark MyAsset as serializable and it will show up in the inspector nicely.
[System.Serializable]
public class MyAsset : ScriptableObject
{
}
No, it doesn't work that way. If $$anonymous$$yAsset
didn't inherit from ScriptableObject, then it would work, but then $$anonymous$$yAsset wouldn't be a separate asset, it would be basically just a structure inside of $$anonymous$$yBehavior. And I want it to be a separate asset.
Oh, you're right, sorry. That slipped my $$anonymous$$d somehow. (Do I remove this answer, or just wait for others to downvote it?)