One of the most powerful features of the Unity editor is the ability to create custom windows and inspectors. We have already seen how we can use attributes such as [Range], [ToolTip], [HideInInspector], [HeaderAttribute] etc. to customize a component’s inspector. However, by writing a custom editor script for a component or asset, we can define exactly how the inspector should look, include useful buttons, visual the data etc.

Custom Inspector

One very simple but useful addition to an inspector is a button which can display information about the object, import assets from a folder or toggle pre-defined settings. Consider the following EnemyData scriptable object.

using UnityEngine;

/// <summary>An asset used to store data for an enemy.</summary>
[CreateAssetMenu(fileName = "EnemyData", menuName = "EnemyData", order = 1000)]
public class EnemyData : ScriptableObject
{
  /// <summary>The enemy's health.</summary>
  [Tooltip("The enemy's health.")]
  [Range(0, 100)] public int health;
  /// <summary>The enemy's speed.</summary>
  [Tooltip("The enemy's speed.")]
  [Range(1, 10)] public float speed;

  /// <summary>Returns a string representation of the object.</summary>
  public override string ToString()
  {
    return string.Format("[EnemyData {0}: health={1}, speed={2}]", name, health, speed);
  }
}

By default the editor renders the following inspector for this asset:

By writing a script extending from Editor and overriding the callback OnInspectorGUI, we have complete control over the inspector’s layout. These Editor scripts must be placed in the root or a subdirectory of folder named Editor, generally Assets/Editor but Assets/Imported/DeFuncArt/Editor/Utilities/ would also be valid.

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;

/// <summary>A custom editor script for the EnemyData asset.</summary>
[CustomEditor(typeof(EnemyData))]
public class EnemyDataEditor : Editor
{
  /// <summary>Callback to draw the inspector.</summary>
  public override void OnInspectorGUI()
  {
    //get a reference to the target script
    EnemyData targetScript = (EnemyData)target;
    //draw default inspector for asset's properties
    DrawDefaultInspector();
    //draw a button which prints info to the console
    if(GUILayout.Button(new GUIContent(text: "Print Info", tooltip: "Prints info about the asset to the console.")))
    {
      Debug.Log(targetScript.ToString());
    }
  }
}
#endif

DrawDefaultInspector draws the same, default inspector that we saw above. However, underneath we draw a button, which if pressed, prints debug info to the console:

This example may be quite trivial, however you can see the potential, for instance triggering an import method in EnemyData which imports from XLS file, or a LevelManager which imports an array of LevelData assets from a predefined path.

Custom Window

We can also easily create custom windows in the editor by writing a script extending from EditorWindow and customizing OnGUI.

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;

/// <summary>An EditorWindow to automate the creation of game data assets.</summary>
class CustomWindow : EditorWindow
{
  /// <summary>The current selected option.</summary>
  public static int option = 0;
  /// <summary>An array of strings used as toolbar texts.</summary>
  public static string[] optionNames = { "Yes", "No" };

  //add a menu item named "Import Assets" to the Tools menu (shortcut ALT-CMD-B)
  [MenuItem("Tools/Custom Window")]
  public static void ShowWindow()
  {
    //show existing window instance - if one doesn't exist, create one
    EditorWindow.GetWindow(typeof(CustomWindow));
  }

  /// <summary>Draws the window.</summary>
  private void OnGUI()
  {
    //draw a label
    GUILayout.Label("This is my custom window");
    //draw a toolbar (array of buttons) and assign the selected button index as option
    option = GUILayout.Toolbar (option, optionNames);
    //draw a button which, if triggered, prints info to the console
    if(GUILayout.Button("Print Info")) { PrintToConsole(); }
  }

  /// <summary>Prints to console.</summary>
  private void PrintToConsole()
  {
    Debug.Log("Hello, World!");
  }
}
#endif

Conclusion

Custom inspectors and custom windows are quite powerful and can help not only your workflow, but that of your team. For more info, check google and the gazillion tutorials or start here with this official one.

Further Reading

Manual - Extending the Editor

Scripting API - Editor

Scripting API - Editor.OnInspectorGUI

Scripting API - EditorWindow

Scripting API - EditorWindow.OnGUI

This post was generated from a GitHub repository.