Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
4
Question by Mr.Jwolf · Jul 22, 2012 at 09:36 PM · c#serializedpropertycustom inspectorcustom class

Access SerializedProperty for Custom classes - C#

Hi,

I am trying to create a custom inspector which reads my own custom variable attributes, to change the behavior of the inspector(like [HideInInspector]).

It can be adding tooltips and show/hide variables based on other variables. And I can get most of it to work... for classes that inheritances MonoBehaviour, but for custom classes I cannot, even if I add [System.Serializable], which only makes it visible in the inspector.

Test Project

I have created a project, where it is possible to see it all in action which can be found here.

What I can do and want to do:

I can:

  • add tooltips in the inspector

  • Show/hide variables based on a boolean

  • Show/hide variables based on a enum

Tooltip in the inspector

I can show tooltip in the inspector by adding an " InspectorTooltip("This is a tooltip.)" attribute to a variable.

[InspectorTooltip("The weapon type the player will wield.")] public WeaponType weaponType = WeaponType.Axe;

[InspectorTooltip("Can the player fly?")] public bool CanFly = true;

And the result is: Tooltips in inspector

Hide-show variable based on a boolean

I can hide/show variables based on a boolean by adding an " ShowInInspectorIfBool" attribute to variables:

//Fly variables [InspectorTooltip("Can the player fly?")] public bool CanFly = true;

[InspectorTooltip("How fast the player gain speed while flying.")] [ShowInInspectorIfBool("CanFly", true)] [FloatSliderInInspector(0.5f, 22.5f)] public float flyAcceleration = 0.5f;

[InspectorTooltip("The maximum fly speed")] [ShowInInspectorIfBool("CanFly", true)] public float maxFlySpeed = 10f; And the result is: Hide / show variables based on a boolean

Hide-show variable based on an enum

I can hide-show variables based on an enum by creating a " ShowInInspectorIfEnum" attribute.

//Sword variables [ShowInInspectorIfEnum("weaponType", WeaponType.Sword)] [InspectorTooltip("Used to calculate sword damage. High means more damage.")] public float SwordSharpness = 10;

[ShowInInspectorIfEnum("weaponType", WeaponType.Sword)] [InspectorTooltip("Used to calculate sword damage. High means slower attack speed.")] public float SwordWeight = 5;

[ShowInInspectorIfEnum("weaponType", WeaponType.Sword)] [InspectorTooltip("Used to calculate sword damage. High means more damage.")] public float SwordBaseDamage = 25;

[ShowInInspectorIfEnum("weaponType", WeaponType.Sword)] [InspectorTooltip("Used to calculate sword damage. High means more damage.")] public bool IsTwoHanded = true;

//Axe variables [ShowInInspectorIfEnum("weaponType", WeaponType.Axe)] [InspectorTooltip("Used to calculate axe damage. High means more damage.")] public float AxeheadSize = 4;

[ShowInInspectorIfEnum("weaponType", WeaponType.Axe)] [InspectorTooltip("Used to calculate axe damage. High means slower attack speed.")] public float AxeWeight = 9;

[ShowInInspectorIfEnum("weaponType", WeaponType.Axe)] [InspectorTooltip("Used to calculate axe damage. High means more damage.")] public float AxeBaseDamage = 25;

[ShowInInspectorIfEnum("weaponType", WeaponType.Axe)] [InspectorTooltip("Used to calculate axe damage. High means more damage but slower attack speed.")] [FloatSliderInInspector(1f, 3f)] public float axeHandleLength = 1.5f;
And the result is: Hide/show variables based on a enum

I can do a few things more like:

  • Making a slider for int/float variables

  • Have Custom draw methods in the editor, if you only want to change how ONE variable is displayed

  • I might add other stuff too.

How it works:

I have created a script that inherits Editor to read the attributes and does what they say, it works basically like this(simplified):

public class ExpandedEditor : Editor {

 public override void OnInspectorGUI ()
 {
     var serializedProperties = serializedObject.GetIterator ();
 
     //Tests if there is any visible fields
     if (serializedProperties.NextVisible (true)) {
         //Loops through all visible fields
         do {    
         ShowInInspectorIfBool boolCondition = getAttribute (s_properties);
         ShowInInspectorIfEnum enumCondition = getAttribute (s_properties);
         InspectorTooltip tooltip = getAttribute (s_properties);
 
         //Evaluates the enum and bool conditions
         bool allowedVisibleForBoolCondition = AllowedVisibleForBoolCondition (s_properties, boolCondition);
         bool allowedVisibleForEnumCondition = AllowedVisibleForEnumCondition (s_properties, enumCondition);

         //Tests is the field is visible
         if (allowedVisibleForBoolCondition && allowedVisibleForEnumCondition) {
         
             GUIContent g_content = new GUIContent();
             g_content.text=CreateReadableName (s_properties.name);
             
             //Sets the tooltip if avaiable
             if (tooltip != null)
                 g_content.tooltip = tooltip.Tooltip;
             
         EditorGUILayout.PropertyField (s_property, g_content, true);
             
             
         }
         } while(s_properties.NextVisible (false));
     }

And then to make it work in a script it is just to create an custom editor script that inheritances the ExpandedEditor. Like this:

[CustomEditor(typeof(PlayerScript))] public class PlayerScriptEditor : ExpandedEditor { /*No code needed*/ }

My problem:

I can ONLY do this for classes that inheritance MonoBehaviour. I am using the serialized properties to draw and go through all the visible fields, but I cannot get hold of the serialized properties for custom classes.

I can figure out if it a specific serialized property is a custom class and if it is expanded or not. But cannot get hold of the serialized properties of the custom class which is what I want so I can try and get the attributes for the variables and decide how it is going to be draw. As of now, it will just draw the custom classes like the normal inspector will do it.

Thanks

Update: The test project and link to test project have been updated!

Comment
Add comment · Show 10
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 Mr.Jwolf · Jul 30, 2012 at 03:05 PM 0
Share

No one to the rescue? );

avatar image DESTRUKTORR · Aug 08, 2012 at 04:40 PM 0
Share

... would you $$anonymous$$d pasting the code that you've used for the custom classes? Or at least a "dummy" version of that code? As it stands, without downloading the thing, we have no idea what you could have done wrong...

avatar image whydoidoit · Aug 08, 2012 at 04:45 PM 0
Share

Can you not just construct an instance of a SerializedObject over your custom class and then read them that way?

avatar image Mr.Jwolf · Aug 08, 2012 at 05:11 PM 0
Share

@ DESTRU$$anonymous$$TORR,

The easiest would be just downloading the project (it is less then 1 mb).

But an example of a custom class (from the project) is:

using UnityEngine; using System.Collections;

[System.Serializable] public class JumpData {

[InspectorTooltip("Can the player jump?")] public bool JumpEnabled = true;

[ShowInInspectorIfBool("JumpEnabled", true)] [InspectorTooltip("How high can the player jump?")] public float JumpHeight = 5;

[ShowInInspectorIfBool("JumpEnabled", true)] [InspectorTooltip("How fast does the player move up.")] public float JumpSpeed = 20;

[ShowInInspectorIfBool("JumpEnabled", true)] [InspectorTooltip("The gravity of the jump.")] public float JumpGravity = 2;

[HideInInspector] public bool isJumping = false;

}

avatar image yoyo · Aug 09, 2012 at 05:04 AM 1
Share

Assu$$anonymous$$g you have a $$anonymous$$onoBehaviour that has a field of type JumpData, then I believe you would need "while(s_properties.NextVisible (true));" (not false) -- you want to recurse into the child object to get its properties, yes?

Show more comments

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by j.robichaud · Oct 24, 2012 at 07:49 PM

I did what you intend to do.

Why it does not work as-is: A field (Ex: JumpSpeed) of a field class instance ( Ex: JumpData myJumpData) serialized in a SerializedObject does not belong to the class itself (JumpData) but to the internal data of the SerializeObject. In order to get the real field, you can access it using Reflection on the previous SerializedProperty returning true to hasVisibleChildren (it also includes Array but it does not matter). In my implementation i used a stack of "System.Type" representing the type of the class that has fields where i would push when it has children and pop when "SerializedProperty.depth" is smaller than the head of the stack.

The implementation of your sample project makes is complicated to implement, would need some refactoring.

How to do it (in pseudo-code):

 int depth = 0
 Stack<Type> parentClassTypes
 
 Push SerializedObject.serializedObject.GetType() in parentClassTypes
 
 Loop on the SerializedProperty
    if depth > currentProperty.depth
       pop parentClassTypes
    depth = currentProperty.depth
    var field parentClassTypes.Peek().GetField( currentProperty.name, BindingFlags.Instance | Public | NonPublic )
 
    if field != null
       Do tooltipStuff here
 
       if currentProperty.hasChildren
          push field.FieldType
 
     Show field with tooltip or not
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

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

9 People are following this question.

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

Related Questions

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

Get "this" SerializedProperty ? 1 Answer

How can I get functionality similar to OnValidate for a custom class? 4 Answers

Easy way to set multiple SerializedProperties 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