in Tutorials, Unity

Simple CustomEditor

With this tutorial we will try to explain how to start to use CustomEditor with Lists

A CustomEditor allow us to change the representation of our classes into the Unity Inspector. It makes easier to interact with the script classes associated to Gameobjects, prefabs, etc…

Component without CustomEditor

Component with CustomEditor

Our first step is to create a folder named Editor. It is a special Unity folder name, Unity will automatically load all scripts that modify the behaviour of UnityEditor from this folder. This scripts will NOT be included in final game build, only will be used by the UnityEditor

We will create two more folders: Scripts and Scenes to store the rest of scripts and the scene to save the work

The directory path look like this:

Assets
|_Editor
|_Scripts
|_Scenes

We start with two simple classes, first we create a new script named Data.cs in our folder Scripts and add the following classes:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class BinarySequence
{
    public int numBits = 5;
    public List<bool> bitList;
}
 
public class Data : MonoBehaviour
{
    public BinarySequence sequence;
}

BinarySequence will represent a list of bits

We have clases to be able to be serializated. To do this we add the tag [System.Serializable] above classes. We can extract the attributes in our editor class in the next step.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
 
//The Serializable attribute lets you embed a class with sub properties in the inspector.
[System.Serializable]
public class BinarySequence
{
    public int numBits = 5;
    public List<bool> bitList;
}
 
[System.Serializable]
public class Data : MonoBehaviour
{
    public BinarySequence sequence;
}

Now we make our custom editor class, creates a new script on Editor named DataEditor and we import the needed editor class width using UnityEditor;.

We add the tag [CustomEditor(typeof(Data))] to say that we will define the representation of the class Data into the editor
DataEditor inherits Editor
Override OnInspectorGUI(), this method will be called with each editor event

using UnityEngine;
using UnityEditor;
using System.Collections;
 
[CustomEditor(typeof(Data))]
public class DataEditor : Editor
{
    /** Update with each inspector event*/
    public override void OnInspectorGUI ()
    {
        //Insert code here
    }
}

Our first task is to add:

serializedObject.Update();  //update the serializazed object of Data<br>
// Insert code here<br>
serializedObject.ApplyModifiedProperties(); //apply property modifications

Now we can continue with the GUI

Add an info text with LabelField

EditorGUILayout.LabelField("Binary sequence");

Extract the attribute ‘sequence’ using the attribute name with the serialized object and FindProperty

SerializedProperty sequenceProperty = serializedObject.FindProperty("sequence");

To extract the BinarySequence attributes we can use the attribute name and FindPropertyRelative because of we will use the previous extracted property.

SerializedProperty bitListProperty = sequenceProperty.FindPropertyRelative("bitList");
SerializedProperty newSizeList = sequenceProperty.FindPropertyRelative("numBits");

If we add now the script Data to an object the list will be created with size 0 and we can not see anything. To change this we will override the size using the numBits attribute of BinarySequence.

The variable bitListProperty contain a serialized object of type List, therefore we can access to the attributes of the class List using FindPropertyRelative the same way we did before

/** set default size */
bitListProperty.FindPropertyRelative("Array.size").intValue = newSizeList.intValue;
int size = bitListProperty.FindPropertyRelative("Array.size").intValue;

To draw our list we begin with a horizontal Layout and add a flexible spaces to each of the sides, so items will remain together even if we change the size of the editor.

EditorGUILayout.BeginHorizontal(); 
GUILayout.FlexibleSpace();
//Insert code here
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();

Our last step is to add the list elements, to do that we will use a toggle for each element. The value of the toggle must ve reasigned to store the new value each time we check it into the editor.

EditorGUIUtility.labelWidth = 2;
for (int i = 0; i < size ; ++i)
{
    bitListProperty.GetArrayElementAtIndex(i).boolValue = EditorGUILayout.Toggle(" ",bitListProperty.GetArrayElementAtIndex(i).boolValue);
}

Five toggles will be created without name. By default the inspector reserve the name space even if we put it empty, to minimize the space reserve we can use labelWidth with a small value.

Finally this is the DataEditor code:

using UnityEngine;
using UnityEditor;
using System.Collections;
 
[CustomEditor(typeof(Data))]
public class DataEditor : Editor
{
    /** Update with each inspector event*/
    public override void OnInspectorGUI ()
    {
     
        serializedObject.Update();
        EditorGUILayout.LabelField("Binary sequence");
        SerializedProperty sequenceProperty = serializedObject.FindProperty("sequence");
         
        SerializedProperty bitListProperty = sequenceProperty.FindPropertyRelative("bitList");
        SerializedProperty newSizeList = sequenceProperty.FindPropertyRelative("numBits");
         
        /** set default size */
        bitListProperty.FindPropertyRelative("Array.size").intValue = newSizeList.intValue;
        int size = bitListProperty.FindPropertyRelative("Array.size").intValue;
         
        EditorGUIUtility.labelWidth = 2;
        EditorGUILayout.BeginHorizontal();
         
        GUILayout.FlexibleSpace();
        for (int i = 0; i < size ; ++i)
        {
            bitListProperty.GetArrayElementAtIndex(i).boolValue = EditorGUILayout.Toggle(" ",bitListProperty.GetArrayElementAtIndex(i).boolValue);
        }
        GUILayout.FlexibleSpace();
        EditorGUILayout.EndHorizontal();
 
        serializedObject.ApplyModifiedProperties();
    }
}

Now, every time that we add the script Data to an object we can see:

sequence_selector

Tutorial files

Support this blog!

For the past year I've been dedicating more of my time to the creation of tutorials, mainly about game development. If you think these posts have either helped or inspired you, please consider supporting this blog. Thank you so much for your contribution!

Write a Comment

Comment