Learn Unity Editor Scripting: Component Inspector Editors (Part 3)
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.
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 theGameManager
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.
Code explanation:
OnEnable
callback gets called for every new component Inspector. Just like theOnEnable
callback forMonoBehaviour
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
andstyleInvalid
with different text colors for when the scene setup is valid or invalid. - In
OnEnable
we setup the styles and cache the targetGameManager
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.
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:
- By modifying the serialized properties and serialized objects.
- By modifying the
MonoBehaviour
orScriptableObject
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
andlevel
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 theOnInspectorGUI
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”.
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).