I’ve been tinkering around with the custom inspectors a lot lately in Unity. Namely PropertyDrawers, which funny enough I have been calling “drawers” to date, as in the drawer of a dresser or bureau. I only this week realized it’s ‘draw-er’, like one who draws. There’s a few limitations to PropertyDrawers that I don’t like, but for the most part they’re damn powerful little things that allow for some interesting things. I’d love to touch on a few drawers I created that perform pretty useful yet generic tasks in Unity.
For starters, for anyone who doesn’t know what a PropertyDrawer is, I suggest heading over to the Unity article on the topic. In that article you will find that you can associate a PropertyDrawer directly to a data type. Or you can associate a PropertyDrawer with an attribute, which allows you to loosely couple your PropertyDrawer to any field that is attributed as such. Today I will be covering two simple examples of a PropertyDrawer that are associated directly with a property, and associated with an attribute. Later I’ll cover a special type of PropertyDrawers I created as an extension to the PropertyDrawer system that I call PropertyModifiers.
Lets first cover the most simple PropertyDrawer that can be associated with a type directly. Here is a serializable class I create call VariantReference. Sometimes when creating components I have a need to allow the user in the unity designer to associate some extra parameters that may be passed on to something else. Lets say for instance I have a Trigger script that when activated calls the ‘Trigger’ method on a TriggerableMechanism script I have on another GameObject.
This Trigger method accepts an optional argument of type object, depending on what type of TriggerableMechanism we target. We want the designer to be able to choose the type of object to send, store and serialize that value, and also draw the appropriate property field for that type. A VariantReference allows this by acting as a wrapper around a value of a configurable type, we restrict these types to those that are unique to the unity design process. Now I can just add a field to the Trigger of type VariantReference and store this value there.
Now we need to write up that PropertyDrawer to draw the proper inspector. It will create a drop down box with the available types, as well as a input field to define the value based on the type. So I create the VariantReferencePropertyDrawer to accomplish just this.
Another common inspector I wanted in the designer for unity was a way to select a tag from a list of tags instead of just a string field. Because tags are stored in strings, I couldn’t just make a PropertyDrawer for some ‘tag’ type. Instead I create an attribute that can be associated with a string that tells the inspector to draw a popup with all the tags as options.
The attribute itself is fairly simple.
[System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = false)]
public class TagSelectorAttribute : PropertyAttribute
public bool AllowUntagged;
And the TagSelectorPropertyDrawer is actually fairly simple as well. I merely use the UnityEditorInternal namespace to get a reference to all the tags, and create a string popup from that. I also allow for ‘Untagged’ as an option in the attribute which include or excludes it as a choice in the popup. From what I understand the UnityEditorInternal namespace is subject to change, so this ‘could’ break in the future. But it’s such a basic method that a fix should be relatively simple.
public class TagSelectorPropertyDrawer : PropertyDrawer
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
if (property.propertyType == SerializedPropertyType.String)
EditorGUI.BeginProperty(position, label, property);
var attrib = this.attribute as TagSelectorAttribute;
property.stringValue = EditorGUI.TagField(position, label, property.stringValue);
var tags = (from s in UnityEditorInternal.InternalEditorUtility.tags where s != SPConstants.TAG_UNTAGGED select new GUIContent(s)).ToArray();
var stag = property.stringValue;
int index = -1;
for(int i = 0; i < tags.Length; i++)
if(tags[i].text == stag)
index = i;
index = EditorGUI.Popup(position, label, index, tags);
if(index >= 0)
property.stringValue = tags[index].text;
property.stringValue = null;
EditorGUI.PropertyField(position, property, label);