Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Deadcow_ · Aug 24, 2015 at 02:04 PM · inspectorscriptableobjectserializedproperty

Draw ScrptableObject inspector in other inspector

I want to share some data between instances of a prefab and I need to be sure this data is the same, either prefab changes applied or not. I decided to use ScriptableObject instance for this, and now I need to display SO properties in the Inspector of script, where SO is a public property.

So... I made empty property attribute

 public class DisplayScriptableObjectPropertiesAttribute : PropertyAttribute
 {
 }

and custom property drawer

 [CustomPropertyDrawer(typeof(DisplayScriptableObjectPropertiesAttribute))]
 public class DisplayScriptableObjectPropertiesDrawer : PropertyDrawer
 {
  // Draw the property inside the given rect
  public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  {
      EditorGUI.PropertyField(position, property);
  }
 }

...but since I'm not too experienced with SerializedProperty I dont know how to display child properties in generic way if SerializedProperty is a ScriptableObject.

My use case

 [Serializable]
 [CreateAssetMenu]
 public class GameManagerSettings : ScriptableObject
 {
  [SerializeField] public bool SharedBool;
 }

 public class GameManager : MonoBehaviour
 {
  [DisplayScriptableObjectProperties]
  public GameManagerSettings Settings;
 ...
 }

and I need to display "SharedBool" in "GameManager" inspector.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
7
Best Answer

Answer by Deadcow_ · Aug 25, 2015 at 10:23 AM

Okay, I find the way to do it. My code probably is not as good as it may be (especially in GetPropertyHeight function), but it did the trick.

 [CustomPropertyDrawer(typeof(DisplayScriptableObjectPropertiesAttribute))]
 public class DisplayScriptableObjectPropertiesDrawer : PropertyDrawer
 {
     // Draw the property inside the given rect
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {
         var e = Editor.CreateEditor(property.objectReferenceValue);
 
         position.height = 16;
         EditorGUI.PropertyField(position, property);
         position.y += 20;
 
         if (e != null)
         {
             position.x += 20;
             position.width -= 40;
             var so = e.serializedObject;
             so.Update();
 
             var prop = so.GetIterator();
             prop.NextVisible(true);
             while (prop.NextVisible(true))
             {
                 position.height = 16;
                 EditorGUI.PropertyField(position, prop);
                 position.y += 20;
             }
             if (GUI.changed)
                 so.ApplyModifiedProperties();
         }
     }
 
     public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
     {
         float height = base.GetPropertyHeight(property, label);
         var e = Editor.CreateEditor(property.objectReferenceValue);
         if (e != null)
         {
             var so = e.serializedObject;
             var prop = so.GetIterator();
             prop.NextVisible(true);
             while (prop.NextVisible(true)) height += 20;
         }
         return height;
     }
 }

this is my SO:

 [Serializable]
 [CreateAssetMenu]
 public class GameManagerSettings : ScriptableObject
 {
     public bool MyBool;
     public int MyInt;
 }

where I use it:

 public class GameManager : MonoBehaviour
 {
     [DisplayScriptableObjectProperties]
     public GameManagerSettings Settings;
 ...

and how it's looks like: alt text

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image ThomLaurent · Mar 24, 2017 at 03:17 PM 1
Share

Just for your information, you don't need to create an Editor (which is overkill) to access its SerializedObject field, you can just simply var soso = new SerializedObject(property.objectReferenceValue);

avatar image
3

Answer by Neikice · Aug 22, 2016 at 11:14 AM

Deadcow_ ,Thanks for your answer. On top of your Foundation, I modified some code. Now correctly displays information about children and SerializedPropertys .

 [CustomPropertyDrawer(typeof(DisplayScriptableObjectPropertiesAttribute))]
 public class DisplayScriptableObjectPropertiesDrawer : PropertyDrawer
 {
     bool showProperty = false;
     float DrawerHeight = 0;
     string button = "-";
     // Draw the property inside the given rect
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {
         var e = Editor.CreateEditor(property.objectReferenceValue);
         var indent = EditorGUI.indentLevel;


     Rect temp = new Rect(position.x , position.y,16 , 16);

     if (GUI.Button(temp, button))
         if (showProperty)
         {
             showProperty = false;
             button = "-";
         }
         else
         {
             showProperty = true;
             button = "|";
         }

         DrawerHeight = 0;
         position.height = 16;
         EditorGUI.PropertyField(position, property);
         position.y += 20;

         if (!showProperty) return;

         if (e != null)
         {
             position.x += 20;
             position.width -= 40;
             var so = e.serializedObject;
             so.Update();

             var prop = so.GetIterator();
             //Debug.Log(" prop.hasVisibleChildren " + prop.hasVisibleChildren);
             prop.NextVisible(true);

             int depthChilden = 0;
             bool showChilden = false;

             while (prop.NextVisible(true))
             {

                 if (prop.depth == 0) { showChilden = false; depthChilden = 0; }

                 if (showChilden && prop.depth > depthChilden)
                 {
                     continue;
                 }
                 position.height = 16;

                 EditorGUI.indentLevel = indent + prop.depth;

                 if (EditorGUI.PropertyField(position, prop))
                 {
                     showChilden = false;
                 }
                 else
                 {
                     showChilden = true;
                     depthChilden = prop.depth;
                 }

                 position.y += 20;
                 SetDrawerHeight(20);
             }
            

             if (GUI.changed)
             {
                 so.ApplyModifiedProperties();
             }
         }
     }

 public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
 {
     float height = base.GetPropertyHeight(property, label);
     height += DrawerHeight;
     return height;
 }

 void SetDrawerHeight(float height)
 {
     this.DrawerHeight += height;
 }

}

alt text

alt text


sp160822-180548.png (4.5 kB)
sp160822-180605.png (10.5 kB)
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by MaDDoX · Aug 28, 2020 at 12:02 AM

Outstanding, best free SO inlining solution I found anywhere. I've fixed a minor button overlapping issue and turned it into a Unity package, to make it easier for others. Tested and working perfectly on Unity 2020.1. Kudos to everyone who contributed to this!

http://bit.ly/displayscriptableobjectproperty

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by stepan-stulov · Aug 24, 2015 at 08:18 PM

Unity mimics true object referencing when working with instances of ScriptableObject and its subclasses. Which conceptually implies drag'n'dropping objects onto fields of the corresponding type. What you can also do is double-click on such field, and you will be sent directly to the inspector of the instance of the game manager settings.

There is another tool within Unity serialization, that enables inline editing in contrast with ScriptableObject — classes that don't extend anything (well System.Object) and that are marked with [Serializable] attribute. Such classes will be edited in place, but won't exist outside of the owner. That said, this is not impossible to do what you want, but are these [Serializable] classes actually what you want?

My rule of thumb for deciding between drag'n'drop or inline is based on answering a simple question: will you reuse the instance? If yes — drag'n'drop (ScriptableObject), if not — inline ([Serializable] class).

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Deadcow_ · Aug 25, 2015 at 10:19 AM 0
Share

Yes, the main purpose is to reuse single SO instance with different prefab instances, but thanks anyway

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

29 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Replicate "Apply" and "Revert" button functionality in ScriptableObject Editor Inspector 2 Answers

How to work with custom class (ScriptableObject) SerializedProperty? 1 Answer

Unity inspector field overlap with eachother 1 Answer

Error when trying to Serialize a field that is in a class 0 Answers

Custom Inspector: Using 'serializedObject' to access inherited members 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges