Download

In this tutorial you’ll learn how to extend the Unity3D’s editor so you can make better use of it in your project. You’ll learn how to draw your own gizmo, create and delete objects in code, create editor windows, use components, and allow the user to undo any action they take with your script.

This tutorial assumes you already know the basics of Unity workflow. If you know how to create objects, prefabs, scenes, move around in the editor, attach components then you are good to go!


Final Result Preview

Let’s take a look at the final result we will be working towards:

Changing the grid color from the window.

As you can see, we’ll be creating an editor window, and a color picker whose selection we’ll use to draw a grid. We’ll also be able to create and delete objects, snapped to this grid, and undo such actions.


Step 1: Gizmos

First we’ll learn how to use gizmos. Here are a few examples of built-in gizmos.

Gizmo used to move an object around.

This is the one you’ll probably see the most in Unity, since it’s drawn for every object that has a Transformcomponent attached to it – so basically every selected object will have this gizmo drawn.

Box collider's gizmo.

Here’s another gizmo, which enables us to see the size of the BoxCollider attached to our game object.


Step 2: Create a Grid Script

Create a C# script that we can use to draw our own gizmo for an object; we’ll draw a simple grid in the editor as an example.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
using UnityEngine;
using System.Collections;
 
public class Grid : MonoBehaviour
{
 
    void Start ()
    {
    }
 
    void Update ()
    {
    }
}

For a grid we need to add two variables, the width and the height.

04
05
06
07
08
09
10
11
12
13
14
15
16
public class Grid : MonoBehaviour
{
    public float width = 32.0f;
    public float height = 32.0f;
 
    void Start ()
    {
    }
 
    void Update ()
    {
    }
}

To draw in the editor we need to use OnDrawGizmos callback, so let’s create it.

04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public class Grid : MonoBehaviour
{
    public float width = 32.0f;
    public float height = 32.0f;
 
    void Start ()
    {
    }
 
    void Update ()
    {
    }
 
    void OnDrawGizmos()
    {
    }
}

Step 3: Draw the Grid

To draw a grid we need a set of horizontal and vertical lines and the position of the editor’s camera so we know around which point we should draw our grid. First, let’s save the camera’s position to a separate variable.

17
18
19
20
void OnDrawGizmos()
{
    Vector3 pos = Camera.current.transform.position;
}

As you can see, we can get the editor’s camera by using the Camera.current reference.

Now we’ll need two for loops that will draw the horizontal and vertical lines.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void OnDrawGizmos()
{
    Vector3 pos = Camera.current.transform.position;
 
    for (float y = pos.y - 800.0f; y < pos.y + 800.0f; y+= height)
    {
        Gizmos.DrawLine(new Vector3(-1000000.0f, Mathf.Floor(y/height) * height, 0.0f),
                        new Vector3(1000000.0f, Mathf.Floor(y/height) * height, 0.0f));
    }
 
    for (float x = pos.x - 1200.0f; x < pos.x + 1200.0f; x+= width)
    {
        Gizmos.DrawLine(new Vector3(Mathf.Floor(x/width) * width, -1000000.0f, 0.0f),
                        new Vector3(Mathf.Floor(x/width) * width, 1000000.0f, 0.0f));
    }
}

To draw lines we use Gizmos.DrawLine(). Note that the Gizmos class has a lot of other drawing API methods, so it is possible to draw such primitives as cube or sphere or even their wireframes. You can also draw an image if you need to.

The grid lines should be infinitely long but float.positiveInfinity and float.negativeInfinitydidn’t seem to work well with drawing the lines, so we can simply put arbitrarily large numbers instead of those. Also, the number of lines strictly depend on the constants we put in the for loops’ definitions; technically we shouldn’t leave those constants like that but it’s just a test code.

To see the grid, create an empty object and attach our script to it:

The grid.

Step 4: Create a Custom Inspector

The next thing to cover is customizing the inspector. To do that we need to create an editor script. Create a new C# file and name it GridEditor. This script should be placed in the Editor folder; if you don’t have one then create it now.

1
2
3
4
5
6
7
8
using UnityEngine;
using UnityEditor;
using System.Collections;
 
[CustomEditor (typeof(Grid))]
public class GridEditor : Editor
{
}

This time we also need to use UnityEditor to be able to make use of the editor classes and functions. To override the default inspector of our Grid object we need to add an attribute before our class declaration,[CustomEditor (typeof(Grid))] lets Unity know that we’ll be customising the Grid‘s inspector. To be able to use the editor callbacks, we need to derive from the Editor class instead of MonoBehaviour.

To change the current inspector we need to override the old one.

06
07
08
09
10
11
public class GridEditor : Editor
{
    public override void OnInspectorGUI()
    {
    }
}

If you check the grid object’s inspector in the editor now, it’ll be empty even though the object itself has some public members. That’s because by overriding the OnInspectorGUI() we discarded the default inspector in order to make a custom one instead.

The grid object's inspector.

Step 5: Use GUILayout to Fill the Custom Inspector

Before we create any fields we need to get a reference to the object that inspector applies to. We actually have its reference already – it’s named target – but for convenience we’ll create a reference to the Gridcomponent of that object. First, let’s declare it.

6
7
8
public class GridEditor : Editor
{
    Grid grid;

We should assign it in OnEnable() function which is called as soon as the inspector is enabled.

06
07
08
09
10
11
12
13
public class GridEditor : Editor
{
    Grid grid;
 
    public void OnEnable()
    {
        grid = (Grid)target;
    }

Let’s create some inspector fields now. We’ll use GUILayout and EditorGUILayout classes for that.

15
16
17
18
19
20
21
public override void OnInspectorGUI()
{
    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Width ");
    grid.width = EditorGUILayout.FloatField(grid.width, GUILayout.Width(50));
    GUILayout.EndHorizontal();
}

The first line, GUILayout.BeginHorizontal(); indicates that we want to place the following inspector elements next to each other, left to right. As you may imagine, the last line,GUILayout.EndHorizontal(); indicates that we no longer want to do that. The actual items are in between those two lines. The first one is a simple label (in our case it will be displaying Grid Width text), and then next to it we create a EditorGUILayout.FloatField which is as you may imagine a float field. Note that we’re assigning grid.width to the value of that FloatField, and the float field itself shows the value of grid.width. We also set its width to 50 pixels.

Let’s see if the field is added to the inspector:

The grid object's inspector.

Step 6: Fill the Inspector and Repaint the Scene

Now let’s add one more item to the inspector; this time it will be grid.height.

15
16
17
18
19
20
21
22
23
24
25
26
public override void OnInspectorGUI()
{
    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Width ");
    grid.width = EditorGUILayout.FloatField(grid.width, GUILayout.Width(50));
    GUILayout.EndHorizontal();
 
    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Height ");
    grid.height = EditorGUILayout.FloatField(grid.height, GUILayout.Width(50));
    GUILayout.EndHorizontal();
}

That’d be all for our grid object fields, if you want to know about other fields and items that you can use in the inspector then you can visit the Unity reference pages on EditorGUILayout and GUILayout.

Note that the changes we make in our new inspector are visible only after we select the Scene View window. To make them visible once they are made we may call SceneView.RepaintAll().

15
16
17
18
19
20
21
22
23
24
25
26
27
28
public override void OnInspectorGUI()
{
    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Width ");
    grid.width = EditorGUILayout.FloatField(grid.width, GUILayout.Width(50));
    GUILayout.EndHorizontal();
 
    GUILayout.BeginHorizontal();
    GUILayout.Label(" Grid Height ");
    grid.height = EditorGUILayout.FloatField(grid.height, GUILayout.Width(50));
    GUILayout.EndHorizontal();
 
    SceneView.RepaintAll();
}

Now we don’t have to click outside the inspector to see the results of the changes.

The updated grid.

Step 7: Handle the Editor Input

Now let’s try to handle the editor’s input, just like we would do it in the game. Any key or mouse states should be available to us. To have this functionality we have to add a onSceneGUIDelegate callback to ourSceneView. Let’s call our update function GridUpdate().