informa
Featured Blog

Make your tools in Unity editor

The right tools can save you a lot of time, and the best tool is the one that fits precisely your needs. Unity allows you to easily improve your editor through custom tools, and this post will introduce some of them.

The path editor for my game in progress

With Unity, you can save a lot of time by creating some tools adapted to your specific needs. Right above, a small path editor I made to save me some time when creating enemy patterns in my current project, Red Skies. With just a few click, I quickly design the general shape I want, then I can perfect it using the transform coordinates.

The Unity editor offers a LOT of tools to make yours, but I will just cover some basics in this post, then it will be up to you to look at the APIs to discover hidden gems.

WARNING: This post is ALL about code, with (commented) snippets rather than theory; that’s the way I like to learn, I hope I’m not alone!

 


Custom inspector

The most common tool you can use to make your life easier is custom inspector.

A very basic way to improve your inspectors is to use Property Attributes, which do not require to rewrite the entire inspector, but rather make it more readable:

So simple, yet so beautiful

using UnityEngine;

 

public class MyScript : MonoBehaviour

{

   [Header("First category")]

    [Tooltip("Primary name for MyScript.")]

    public string scriptName;

    public float scriptFloat;

 

    [Header("Second category")]

    [Tooltip("Secondary name for MyScript.")]

    public string secondaryName;

}

 

And then you can go pretty crazy with the custom inspectors themselves. Those scripts are editor-side only (they have to inherit from Editor and be placed in a folder called Editor) and let you write what you want, how you want, in the inspector when an instance of your script is selected. There is a ton of functions to experiment with, that can be found in various editor classes such as EditorGUILayout;, GUILayout;, EditorGUIUtility; and many others, ranging from simple to highly customizable.

I bet it could be of some use… maybe… for a weird project

using UnityEngine;

using UnityEditor;

 

//This line will automatically call your custom editor for instances of MyScript

[CustomEditor(typeof(MyScript))]

public class MyScriptInspector : Editor

{

    //Keep a reference on your style rather than regenerating them every update

    GUIStyle headerStyle;

 

    //This custom inspector will generate random ids in order to display a list to

    // the user from which he can then choose

    bool choosingNewId = false; //Are options displayed?

    string[] newIds; //Random ids generated to choose from

 

    public override void OnInspectorGUI()

    {

       //The member "target" allow you to grab a ref to the instance of your component

      MyScript myScriptTarget = (MyScript) target;

 

      //Init styles

      if(headerStyle == null)

      {

         InitStyles();

      }

 

      EditorGUILayout.Space();

      EditorGUILayout.LabelField("First Category", headerStyle);

      EditorGUILayout.LabelField("Script id: " + myScriptTarget.scriptName);

 

      //If player has already clicked on the "Generate new name" button,

      // then we only display the generated options

      if(choosingNewId)

      {

         for(int i = 0; i < newIds.Length; i++)

         {

            if(GUILayout.Button(newIds[i]))

            {

               myScriptTarget.scriptName = newIds[i];

               choosingNewId = false;

            }

         }

      }

      else if(GUILayout.Button("Generate new name"))

      {

         newIds = new string[] { Random.Range(0, int.MaxValue).ToString(),

         Random.Range(0, int.MaxValue).ToString(),

         Random.Range(0, int.MaxValue).ToString() };

         choosingNewId = true;

      }

   }

 

   void InitStyles()

   {

      headerStyle = new GUIStyle();

      headerStyle.fontStyle = FontStyle.Bold;

      headerStyle.normal.textColor = Color.yellow;

   }

}

 

Note that I could have used a PopUp to display the choices in another way (there are many other solutions, I guess, but the EditorGUILayout.PopUp is pretty neat).

You just indicate the class for which you want to make your custom inspector, then the OnInspectorGUI is ready to make all your dreams come true. The EditorGUILayout and GUILayout classes are usually the more convenient to use, since you don’t have to handle the position and size of your elements, but you can use EditorGUI and GUI as well for very precise display (you could recreate, say, a color picker in the inspector by drawing a bunch of colored pixels and using the events of the mouse).

There are of course some limitations and tricky cases, but it’s up to you to find out about those according to your needs.

 


Editor windows

Did I speak about your custom color picker? Well why not, after all! Let’s make it in a small window, so that it doesn’t take all the space in the inspector. Editor windows use the same apis as custom inspector. To spice things up, we’ll allow the user to select the amount of color he wants to be able to choose from. (It’s not a course about color, so forgive me if my color theory isn’t perfect!)

A color picker, not the best idea for a gif… but I spent way too much time doing it to change it now

using UnityEngine;

using UnityEditor;

 

public class DiscreteColorPicker : EditorWindow

{

   //Create and open a discrete color picker

   [MenuItem("Window/Open Discrete color picker")]

   public static void OpenDiscreteColorPicker()

   {

      DiscreteColorPicker windowInstance = ScriptableObject.CreateInstance<DiscreteColorPicker>();

      windowInstance.Init();

      windowInstance.Show();

   }

 

   int division = 1; //Base value to calculate amount of available colors

   int colorAmount

   {

      //There are {pickerTextureHeight} base color to choose from, each generating

      // a grid of {luminosityTextureSize}*{luminosityTextureSize} tints, with

      // the last line being only black squares.

      get { return pickerTextureHeight * luminosityTextureSize * luminosityTextureSize - luminosityTextureSize + 1; }

   }

 

   Color currentBaseColor; //Current selected base color

 

   Vector2 currentLuminosityCoordinates; //Coordinates of selected tint in luminosity texture

   float currentMainColorY = -1f; //Coordinate of selected base color

 

   Texture2D pickerTexture; //Texture containing the base colors

   Texture2D luminosityTexture; //Texture based on the current base color with luminosity variations

   Texture2D cursorTexture; //Texture used to display cursors

   Texture2D sampleColorTexture; //Texture containing final color

 

   int pickerTextureHeight

   {

      get { return division * 6; }

   }

   int luminosityTextureSize

   {

      get { return division * 3; }

   }

 

   int pickerSize = 300; //GUI object size

 

   bool draggingLuminosity; //Is user dragging from luminosity square

   bool draggingColor; //Is user dragging from color picker

 

   void OnGUI()

   {

      EditorGUILayout.LabelField("Discrete color");

 

      EditorGUI.indentLevel++;

 

      //First, a slider to decide the amount of colors

      bool needsUpdate = false;

      int newDivision = EditorGUILayout.IntSlider("Color levels:", division, 1, 30, GUILayout.MaxWidth(pickerSize));

      if(newDivision != division)

      {

         //If division changed, update luminosity coordinates to adapt to new grid

         currentLuminosityCoordinates *= ((float) newDivision) / ((float) division);

         division = newDivision;

 

         //Then regenerate textures, since their size has changed

         RegenerateTextures();

         needsUpdate = true;

      }

      EditorGUILayout.LabelField("=> " + colorAmount + " colors");

      GUILayout.Space(10);

 

      //Reserve a rect in the windows, where we can draw with GUI functions, and that

      // GUILayout functions will consider as already filled

      Rect colorPickerRect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, pickerSize);

 

      //Draw luminosity texture

      Rect luminosityRect = new Rect(colorPickerRect);

      luminosityRect.x += 5;

      luminosityRect.width = pickerSize;

      GUI

Latest Jobs

Infinity Ward

Woodland Hills, California
11.3.21
Sr. Multiplayer Design Scripter/Programmer

Disbelief

Cambridge, Massachusetts
11.3.21
Jr. Programmer

XSEED

Torrance, California
11.3.21
Head of Marketing
More Jobs   

CONNECT WITH US

Register for a
Subscribe to
Follow us

Game Developer Account

Game Developer Newsletter

@gamedevdotcom

Register for a

Game Developer Account

Gain full access to resources (events, white paper, webinars, reports, etc)
Single sign-on to all Informa products

Register
Subscribe to

Game Developer Newsletter

Get daily Game Developer top stories every morning straight into your inbox

Subscribe
Follow us

@gamedevdotcom

Follow us @gamedevdotcom to stay up-to-date with the latest news & insider information about events & more