Learn Unity Editor Scripting: Component Inspector Editors (Part 3)

No Such Dev
8 min readOct 21, 2020

In this post we will learn how to create custom inspector editors for different components (our MonoBehaviour and ScriptableObject). You can tell Unity Editor how exactly you want the Inspector UI for your components to look like.

This article is part of a series in which I explain all the techniques for extending the Unity Editor. See the overview post here.

Prerequisite: You need to know C# programming and be familiar with Unity Editor to benefit most from this post. You also need to be familiar with Unity’s IMGUI. I’ll make a tutorial on IMGUI soon. Until then, you can refer to Unity documentation.

There is an accompanying Unity project. I highly recommend downloading it and trying the topics as you read them here. Seeing the examples in action makes them stick to your brain.

For instructions on how to get started with the project, see the overview post.

Without further ado, let’s jump in!

1. Custom Editor for GameManager Component

We are going to create a custom editor for the GameManager class. With a custom Editor we can show our own GUI in the inspector window for our components. In the project, select the “Manager” object and note how the inspector UI looks like for it. The manager object is a singleton and manages the UI and victory / lose conditions.

The default Inspector for our GameManager class.

1.1 Implement the Default Inspector

Similar to Property Drawers in the previous post, we need to create a new “Editor” class (script file should be in an Editor folder) which performs drawing the GUI in inspector. We also need to add an attribute to it so that Unity knows it will be responsible for drawing the inspector GUI for the GameManager component.

Code explanation:

  • Our editor class needs to extend the UnityEditor.Editor class.
  • We can name the class anything. I prefer the <ComponentName>Editor naming convention.
  • The CustomeEditor attribute in line 1 tells Unity to use the class for showing GUI for the GameManager component in Inspector window.
  • We should override OnInspectorGUI which responsible for the GUI of the component in Inspector window.
  • DrawDefaultInspector helper function draws the default GUI for the component.
  • Again we have added a HelpBox at the end to make sure we are seeing our custom editor in Inspector window not the default one.

OnInspectorGUI gets called for each draw of the Inspector GUI for the component. Typically that happens a few times per second, so make sure this method is lightweight. It affects the performance of the Unity Editor.

1.2 Add Validation UI

Next, let’s add a validate button to the inspector. The validation will tell the developer if there are errors in the scene setup. That way if multiple developers are making levels for the game, they will know how to setup the level properly.

Left: Scene setup ok, Right: Scene setup has errors.

Code explanation:

  • OnEnable callback gets called for every new component Inspector. Just like the OnEnable callback for MonoBehaviour s, it is the perfect place for performing any one time setup.
  • target field has a reference to the component our editor is handling.
  • We are using two styles styleValid and styleInvalid with different text colors for when the scene setup is valid or invalid.
  • In OnEnable we setup the styles and cache the target GameManager our editor is handling.
  • In OnInspectorGUI (lines 21 to 30) we add the validate button and show the result of the scene validation.

The validation logic resides in GameManager.cs file. In Unity remove the player tag from the Player game object in the scene and select the Manager object. The inspector should show the error in red like the right image.

After fixing every setup error, then the validation UI should show “All Set!” in green text.

1.3 Custom GUI for a Property of the GameObject

So far we have learnt how to create custom Inspector UI for a component, access the backing component directly. Next let’s make changes to the component from the Editor. DrawDefaultInspector helper did all the heavy lifting for us.

Let’s create a custom UI for the levelName field. Instead of the default textbox, which let’s the developers choose any random name, we show an int dropdown and set the name from the number selected from the dropdown. This way we make sure the level names will always be in Level X format.

Our custom UI for levelName field.

We already know how to create the GUI using IMGUI and how to write values to serialized properties from the previous post on how to write property drawers. With serialized objects such as components, things are a little more complex. We have two ways to modify our objects:

  1. By modifying the serialized properties and serialized objects.
  2. By modifying the MonoBehaviour or ScriptableObject directly.

We will see how to use both options in the next two subsections.

1.3.1 Using the Serialized Object and Serialized Properties

Here is the new code for showing our new custom UI for the levelname field and writing the changes back to the serialized property and serialized object.

This is the preferred method of writing custom editors. It makes it easier to handle multi-object editing and undo / redo.

Only the additions to the class are shown here.

Code explanation:

  • the levelOptionsInt , levelOptionsStr and level fields are created for showing the dropdown in IMGUI.
  • serializedObject field of editor class gives us a reference to the object we are modifying.
  • serializedObject.Update syncs up the serialized properties in the object with the game object we are modifying. We should call this before making any changes to make sure our values are the most up to date ones.
  • serializedObject.FindProperty let’s us find the properties of the game object we are modifying.
  • serializedObject.ApplyModifiedProperties writes the changes we have made to serialized properties back to the game object. If you comment out this line, the changes made through inspector will not take effect!

Here is how the Inspector looks like:

Everything works fine excepting for levelName field being shown twice. One time by our custom GUI code. Again by the call to DrawDefaultInspector. Luckily we can fix this by adding the HideInInspector attribute to the field as we learnt in part 1. That way the default inspector will hide the levelName field.

Now the UI looks just how we wanted it!

1.3.2 Using the Component Directly

Now let’s modify the OnInspectorGUI method to write the changes back to the component directly, bypassing the serialized object. This may seem more straightforward but needs care as we need to tell Unity what changed which is more prune to errors in my experience. At the end of the day it is your choice which way to go.

From before, replace the Level Name Section of OnInspectorGUI method with the following.

Code Explanation:

  • Undo.RecordObject tells Unity Editor that the object is being modified. Unity Editor will make a snapshot of the object at this point. At the end of the OnInspectorGUI call, Unity Editor will diff the modified object from the snapshot and if there are changes mark scene dirty and add an action to the undo stack.

The UI looks exactly as before and behaves the same. We now have our own action on the undo stack with the label we provided to Undo.RecordObject.

1.4 Multi-object Editing from Our Custom Editor

The custom editors can by default only modify a single object. Let’s create another custom editor, this time for our TargetController component.

Create a file named TargetControllerEditor.cs under the Scripts/Editor folder with this content. (You need to add using s at the top).

Now when a single object is selected, the Inspector shows just fine. But when we select multiple objects (Cubes from the sample scene), the Inspector tells us that “multi-object editing is not supported”.

select multiple objects from the scene or hierarchy.
Left: single object selected, Right: multiple objects selected.

We can tell Unity that our custom editor can handle multi selection by using the CanEditMultipleObjects attribute.

Now the Inspector works just fine. Again we are relying on the magic from DrawDefaultInspector . Let’s get rid of that and implement our own GUI to learn how to handle serialized properties that represent multiple objects.

Code explanation:

  • SerializedProperty can represent properties from multiple objects.
  • serializedProperty.hasMultipleDifferentValues checks to see if all values from the property are the same or not. We use this check in line 7 to show different GUI.
  • We use <multiple values> magic string to mean there are multiple values. If the user changes the value from this, then we write the new value to the property, which will modify it for all the selected objects.

Our UI looks and behaves similar to the default inspector UI.

Conclusion

In this post we learnt:

  • how to create our own Inspector GUI in Unity Editor and use them for our components. We can show our custom UI, add validation and other things with custom editors.
  • We also learnt how to write the changes from Inspector back to the objects.

Next

If you have any questions and suggestions about this post, feel free to leave a comment.

Follow me to get notified of my new posts. I am an indie game developer and regularly write tutorials, tips and tricks and stories about game dev, programming and Unity.

If you find this tutorial useful, please support me on Patreon. It takes a good amount of time to write these tutorials and your support will keep me going. Thank you!

Next we will learn how to create menu items both in the inspector context menus and in the main Unity menus (ETA Oct 28th 2020).

--

--

No Such Dev

Software Engineer | Indie Game Developer | Founder of No Such Studio. Follow me to learn how to make video games with Unity. http://www.nosuchstudio.com