- Home /
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: 
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 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: 
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!
... 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...
Can you not just construct an instance of a SerializedObject over your custom class and then read them that way?
@ 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;
}
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?
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
Your answer
Follow this Question
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