Creating Custom Inspectors in Unity with Editor Scripting


Building a custom inspector in Unity is a great way to provide a personalized and efficient workflow for your RPG. This blog post will show you how to create custom inspectors with Unity’s editor scripting. We’ll use ScriptableObjects and AnimationCurves, which are powerful tools for creating reusable data and controlling changes over time, respectively.

What are Custom Inspectors?

A custom inspector, in Unity parlance, is a user interface for a specific script. Unity’s inspector window lets you edit your game objects, but sometimes you need a custom one for specific functionality or to streamline your workflow.

Getting Started with Custom Inspectors

First, create a new C# script and name it “CustomInspector”. Open the script, and make it inherit from UnityEditor.Editor instead of MonoBehaviour.

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(MyScriptableObject))]
public class CustomInspector : Editor
{
    // code here...
}

In the code above, the CustomEditor attribute tells Unity that this class is a custom inspector for the “MyScriptableObject” class.

Understanding Unity’s GUI Systems for Custom Inspectors

Unity offers multiple systems to handle graphical user interfaces (GUI). When designing custom inspectors, four classes in particular will be your main tools: GUI, GUILayout, EditorGUILayout, and EditorGUI. These classes provide methods for creating and arranging various UI elements such as labels, text fields, buttons, and more.

GUI and GUILayout

GUI and GUILayout classes contain methods to create UI elements with either manual control over positioning and sizing (GUI) or automatic layout features (GUILayout).

public override void OnInspectorGUI()
{
    // GUI example
    if(GUI.Button(new Rect(10, 10, 150, 20), "GUI Button"))
    {
        // Handle button click
    }

    // GUILayout example
    if(GUILayout.Button("GUILayout Button"))
    {
        // Handle button click
    }
}

In the GUI example, the button’s position and size are specified with a Rect. With GUILayout, the button is automatically positioned and sized according to the layout.

EditorGUILayout and EditorGUI

EditorGUILayout and EditorGUI are the Editor counterparts to GUI and GUILayout. They contain methods for creating UI elements specifically designed for use in Unity’s inspector.

public override void OnInspectorGUI()
{
    MyScriptableObject myScriptableObject = (MyScriptableObject)target;

    // EditorGUILayout example
    myScriptableObject.name = EditorGUILayout.TextField("Name", myScriptableObject.name);

    // EditorGUI example
    EditorGUI.LabelField(new Rect(10, 40, 200, 20), "Label:", EditorStyles.boldLabel);

    myScriptableObject.name = EditorGUI.TextField(new Rect(10, 60, 200, 20), myScriptableObject.name);
}

In the EditorGUILayout example, a text field is created with a label and is automatically positioned and sized according to the layout. The EditorGUI example creates a label and text field at specified positions.

Overall, these classes allow you to create a wide variety of custom inspectors tailored to your exact needs. While EditorGUILayout is most commonly used due to its ease and automatic layout, understanding all four classes provides greater flexibility when designing your custom inspectors.

ScriptableObjects

ScriptableObjects in Unity allow for creating highly modular, adjustable, and referable game data. RPGs often feature extensive game data, such as character stats, item properties, or skill descriptions. Here, we create a “MyScriptableObject” which will be the base class for our custom inspector.

using UnityEngine;

[CreateAssetMenu(fileName = "NewData", menuName = "RPG/Data")]
public class MyScriptableObject : ScriptableObject
{
    public string name;
    public AnimationCurve curve;
}

This script creates an asset in Unity’s project window that, when selected, will be edited with our custom inspector. The “AnimationCurve” will be used to demonstrate how to use curves in the inspector.

Building the Custom Inspector

The OnInspectorGUI function controls what appears in the inspector window. Below, we have an example of how you can override this function to create a custom inspector for our ScriptableObject.

public override void OnInspectorGUI()
{
    MyScriptableObject myScriptableObject = (MyScriptableObject)target;
    myScriptableObject.name = EditorGUILayout.TextField("Name", myScriptableObject.name);
    myScriptableObject.curve = EditorGUILayout.CurveField("Curve", myScriptableObject.curve);

    if(GUILayout.Button("Reset"))
    {
        myScriptableObject.curve = AnimationCurve.Linear(0, 0, 1, 1);
    }

    EditorUtility.SetDirty(myScriptableObject);
}

In this example, EditorGUILayout.TextField and EditorGUILayout.CurveField create editable fields for the name and the curve of our ScriptableObject, respectively.

The “Reset” button is created using GUILayout.Button. When clicked, it resets the curve to a linear curve from (0, 0) to (1, 1) using AnimationCurve.Linear.

EditorUtility.SetDirty is used to inform Unity that the ScriptableObject has changed and needs to be saved. Without this, changes made in the custom inspector would not persist.

The Power of AnimationCurves

AnimationCurve is a versatile class that can drastically change the way you handle varying values over time or conditions in your game. It essentially allows you to create a curve that defines how an attribute changes based on an input, which can be time, distance, level, or any other quantifiable data.

Let’s illustrate with a more concrete example. Consider an RPG where characters gain strength as they level up. The increase in strength per level may not be linear; instead, it could be an exponential curve to show a rapid early-game progression that slows down as the character approaches higher levels.

[CreateAssetMenu(fileName = "CharacterData", menuName = "RPG/CharacterData")]
public class CharacterData : ScriptableObject
{
    public string characterName;
    public AnimationCurve strengthGrowthCurve;
}

In our custom inspector, we can edit this curve to accurately represent the desired strength progression. This gives you direct control and a clear visual representation of your character’s strength growth.

[CustomEditor(typeof(CharacterData))]
public class CharacterDataEditor : Editor
{
    public override void OnInspectorGUI()
    {
        CharacterData characterData = (CharacterData)target;
        characterData.characterName = EditorGUILayout.TextField("Character Name", characterData.characterName);
        characterData.strengthGrowthCurve
            = EditorGUILayout.CurveField("Strength Growth Curve", characterData.strengthGrowthCurve);

        if(GUILayout.Button("Reset"))
        {
            characterData.strengthGrowthCurve = AnimationCurve.Linear(0, 0, 1, 1);
        }

        EditorUtility.SetDirty(characterData);
    }
}

You can evaluate the strength of the character at any level by calling strengthGrowthCurve.Evaluate(level), giving you a flexible, intuitive and dynamic way of designing progression in your game. You could also use curves for many other aspects of an RPG, like AI behavior, damage falloff over distance, spawn rates, and so much more.

In essence, AnimationCurves give you a graphical, intuitive way to design game mechanics without hardcoding specific values. When combined with custom inspectors and ScriptableObjects, they provide a powerful, flexible way to design and balance your game.

In conclusion, custom inspectors are a powerful tool in Unity that can drastically improve your workflow and data management. With ScriptableObjects and AnimationCurves, the possibilities are nearly limitless. So, start creating your custom inspectors and enhance the quality of your RPG tools today!

, ,