Loading...

UNITY 3D: Extending The Editor part 2 - Custom Editor for a ScriptableObject

Intro


In this part of the series, we will create a ScriptableObject that will function as our data asset. The data asset will contain a list of data structs that will hold our shortcut information. After we created our ScriptableObject asset, we'll create a Custom Editor for it and use the custom editor to overwrite the default inspector window that Unity draws for us.

 

Fast Travel


If you are only interested in a specific part, you can skip to the section you'd like here. I do however use the same project and files during the entirety of this series. The project's source can be found in the last part of this series.

 

 

Creating the data structure


We’ll create a new C# script and name it TutorialShortcutData.

This class will represent and store our data. Because I like to utilize all of the Unity Environment, I will be using this as a Scriptable Object. To make it a ScriptableObject, replace the MonoBehaviour keyword with ScriptableObject

 

A ScriptableObject is a data container that you can use to save large amounts of data, independent of class instances. One of the main use cases for ScriptableObject's is to reduce your Project’s memory usage by avoiding copies of values. This is useful if your Project has a Prefab that stores unchanging data in attached MonoBehaviour scripts.

See this page for more info

 

using System.Collections.Generic;
using UnityEngine;
​
[CreateAssetMenu(order = 0, fileName = "TutorialShortcutData", menuName = "Shortcut Data")]
public class TutorialShortcutData : ScriptableObject
{
   
}

The line above the class adds a context menu entry to the "Create" menu. Now we can create an instance of this scriptable object that we can use in the editor.

When we create an instance, we don't see much happening. It creates a new file, but it has nothing in it. So let's add a few structures so we can see some data.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
​
[CreateAssetMenu(order = 0, fileName = "TutorialShortcutData", menuName = "Shortcut Data")]
public class TutorialShortcutData : ScriptableObject
{
    public List<ShortcutDataRecord> shortcuts;
​
    [System.Serializable]
    public class ShortcutDataRecord
    {
        [SerializeField]
        private string m_Name;
​
        [FormerlySerializedAs("m_KeyboardRecord")]
        [SerializeField]
        private Binding m_Binding;
​
        public string name => m_Name;
​
        public Binding binding => m_Binding;
    }
​
    [System.Serializable]
    public struct Binding
    {
        [SerializeField]
        private KeyCode m_KeyCode;
​
        [SerializeField]
        private EventModifiers m_Modifiers;
​
​
        public Binding(KeyCode keyCode, EventModifiers modifiers) : this()
        {
            this.m_KeyCode = keyCode;
            this.m_Modifiers = modifiers;
        }
​
        public KeyCode keyCode => m_KeyCode;
​
        public EventModifiers modifiers => m_Modifiers;
​
        public static Binding none => new Binding();
    }
}

We added two new structs that will hold all data necessary to create our shortcut list.

The first struct holds the actual shortcut data which consists of a shortcut name m_Name and m_Binding. This struct will be the object that we see in the inspector window.

The second struct is our binding data. This struct will hold the keycode and key modifier variables.

When we go back to the editor to see our ScriptableObject again, it will look rather dull and not really user-friendly.

The next step to this will be changing this default list view to a neat looking ReorderablelList. We'll do that by adding a Custom Editor.

 

Custom Editor


A Custom Editor is incredibly useful when the default inspector controls just don't cut it anymore. Custom Editors replace the default inspector view and give you the functionality to draw your own controls and fields.

Let's say we have a default list view and we would like to change it to something more user-friendly and easier to manage. We could do that by creating a Custom Editor.

 

So let's get started!


Create a new C# Script and name it TutorialShortcutCustomEditor

A Custom Editor script is created by inheriting from Editor. Then, we need to specify for which Type this Custom Editor exists with the following line:[CustomEditor(typeof(TutorialShortcutData))]

To start drawing the inspector window yourself, you'll need to override the OnInspectorGUI() method. This method is responsible for painting the inspector. To see what it does, remove the base.OnInspectorGUI(); line from the method. You'll see that it just draws nothing.

using UnityEditor;
​
[CustomEditor(typeof(TutorialShortcutData))]
public class TutorialShortcutCustomEditor : Editor
{
    private void OnEnable()
    {
        
    }
    
    public override void OnInspectorGUI()
    {
       base.OnInspectorGUI();
    }
}

To get a reference to TutorialShortcutData we can use the serializedObject property that we inherit from the Editor class.

 

SerializedObject and SerializedProperty are classes for editing serialized fields on Unity objects in a completely generic way. These classes automatically handle dirtying individual serialized fields so they will be processed by the Undo system and styled correctly for Prefab overrides when drawn in the Inspector.

See this page for more info

 

We would, however, like to get a reference to the list we made in our ScriptableObject, so we can change and draw this property. To do just that, we can create a SerializedProperty

using UnityEditor;
​
[CustomEditor(typeof(TutorialShortcutData))]
public class TutorialShortcutCustomEditor : Editor
{
    private SerializedProperty m_shortcutData;
    private void OnEnable()
    {
        m_shortcutData = serializedObject.FindProperty("shortcuts");
    }
    
    public override void OnInspectorGUI()
    {
        //Update serialized object's representation.
        serializedObject.Update();
        
        //Draw the list property we found in the ScriptableObject
        EditorGUILayout.PropertyField(property: m_shortcutData, includeChildren: true);
        
        //Apply any changes made to the serializedObject and flush it's data stream.
        serializedObject.ApplyModifiedProperties();
    }
}

When we check this in the ScriptableObject asset that we made earlier, you'll notice that exactly nothing has changed. We still draw the same ugly list as before. But now, we are in control of what's drawn, so we can start changing it.

 

Conclusion


Now that you know how to override the default inspector we can start looking at changing the way the inspector looks and behaves. See the next part on how to replace the default list view with a nice Reorderable List.

If you have any questions or feedback, please feel free to email me or post a comment in the comment section down below.

 

Further readings and references


Be the first to comment

Post Comment

This website uses cookies to ensure you get the best experience on my website