Categories: Tutorials

An Editor Tool Tutorial

5 min read

Often, when making games, we use different programs to author the various content that goes into our game. When it’s time to stick all the pieces together, things have a habit of catching fire/spiders. Avoiding flaming arachnids is usually a good idea, so in this tutorial, we’re going to learn how to do just that. Note that for this tutorial, I’m assuming that you have some experience writing gameplay code in Unity and want to learn the ways to improve your workflow.

We’re going to write a small editor tool to turn a text file representation of a level, which we’re pretending was authored in an external-level editing program, into an actual level.

We’re going to turn this:

Into this:

Protip:

Before writing any tool, it’s important that you weigh the pros and cons of writing that tool. Many people make the mistake of taking a long time to write a complicated tool, and what ends up happening is that the tool takes longer to write than it would have taken to do the tool’s job manually! Doing stuff manually isn’t fun, but remember, the end goal is to save time, not to show off your automation skills.

First up, let’s understand what our level file is actually telling us. Take a look at the first image again. Every dot is a space character and the two letter words represent different kinds of tiles. From our imaginary-level design program, we know that the keywords are as follows:

  • c1 = cloud_1
  • bo = bonus_tile
  • gr = grass_tile
  • wa = water_tile

We need some way to represent this mapping of a keyword to an asset in Unity. To do this, we’re going to use scriptable objects. What is a scriptable object? From the Unity documentation: “ScriptableObject is a class that allows you to store large quantities of shared data independent from script instances.

They’re most commonly used as data containers for things such as item descriptions, dialogue trees or, in our case, a description of our keyword mapping. Our scriptable object will look like this:

Take look at the source code behind this here. Let’s go through some of the more outlandish lines of code:

[System.Serializable]

This tells Unity that the struct should be serialized. For our purposes, it means that the struct will be visible in the inspector and also retain its values after we enter and exit play mode.

[CreateAssetMenu(fileName = "New Tileset", menuName = "Tileset/New", order = 1)]

This is a nifty attribute that Unity provides for us, which lets us create an instance of our scriptable object from the assets menu. The attribute arguments are described here. In action, it looks like this:

You can also access this menu by right clicking in the project view.

Next up, let’s look at the actual editor window. Here’s what we want to achieve:

It should take a map file, like the one at the start of this tutorial, and a definition of what the keywords in that file map to (the scriptable object we’ve just written), and use that to generate a map where each tile is TileWidth wide and TileHeight tall.

The source code for the TileToolWIndow is available here.

Once again, let’s take a look at the stranger lines of code:

using UnityEditor;

public class TileToolWindow : EditorWindow

To make editor tools, we need to include the editor namespace. We’re also inheriting the EditorWindow class instead of the usual Monobehaviour.

Protip:

When you have using UnityEditor; in a script, your game will run fine in the editor, but will refuse to compile to a standalone. The reason for this is that the UnityEditor namespace isn’t included in compiled builds, so your scripts will be referencing to a namespace that doesn’t exist anymore. To get around this, you can put your code in a special folder called Editor, which you can create anywhere in your Assets folder. What Unity does is that it ignores any scripts in this folder, or subsequent subfolders, when it’s time to compile code. You can have multiple Editor folders, and they can be inside of other folders. You can find out more about special folders here.

[MenuItem("Tools/Tile Tool")]
public static void InitializeWindow() 
{
 TileToolWindow window = EditorWindow.GetWindow(typeof(TileToolWindow)) as TileToolWindow;
 window.titleContent.text = "Tile Tool";
 window.titleContent.tooltip = "This tool will instantiate a map based off of a text file";
 window.Show();  
}

The [MenuItem(“Path/To/Option”)] attribute will create a menu item in the toolbar. You can only use this attribute with static functions. It looks like this:

In the InitializeWindow function, we create a window and change the window title and tooltip. Finally, we show the window. Something to look out for is Editor.GetWindow, which returns an EditorWindow. We have to cast it to our derived class type if we want to be able to use any extended functions or fields.

private void OnGUI()

We use OnGUI just like we would with a MonoBehaviour. The only difference is that we can now make calls to the EditorGUI and EditorGUILayout classes. These contain functions that allow us to create controls that look like native Unity editor UI. A lot of the EditorGUI functions require some form of casting. For example:

EditorGUILayout.ObjectField("Map File", mapFile, typeof(TextAsset), false) as TextAsset;

Remember that if you’re getting compilation errors, it’s likely that you’re forgetting to cast to the correct variable type.

The last strange lines are:

Undo.RegisterCreatedObjectUndo(folderObject.gameObject, "Create Folder Object");

And:

GameObject instantiatedPrefab = Instantiate(currentPrefab, new Vector3(j * tileWidth, i * tileHeight, 0), Quaternion.identity, folderObject) as GameObject; 
Undo.RegisterCreatedObjectUndo(instantiatedPrefab, "Create Tile");

The Undo class does exactly what it says on the tin. It’s always a good idea to allow your editor tool operations to be undone, especially if they follow a complicated set of steps!

The rest of the code is relatively straightforward. If you want to take look at the complete project, you can find it on GitHub.

Thanks for reading!

About the author

Ahmed Elgoni is a wizard who is currently masquerading as a video game programmer. When he’s not doing client work, he’s probably trying to turn a tech demo into a cohesive game. One day, he’ll succeed! You can find him on twitter @stray_train.

Ahmed Elgoni

Share
Published by
Ahmed Elgoni

Recent Posts

Top life hacks for prepping for your IT certification exam

I remember deciding to pursue my first IT certification, the CompTIA A+. I had signed…

3 years ago

Learn Transformers for Natural Language Processing with Denis Rothman

Key takeaways The transformer architecture has proved to be revolutionary in outperforming the classical RNN…

3 years ago

Learning Essential Linux Commands for Navigating the Shell Effectively

Once we learn how to deploy an Ubuntu server, how to manage users, and how…

3 years ago

Clean Coding in Python with Mariano Anaya

Key-takeaways:   Clean code isn’t just a nice thing to have or a luxury in software projects; it's a necessity. If we…

3 years ago

Exploring Forms in Angular – types, benefits and differences   

While developing a web application, or setting dynamic pages and meta tags we need to deal with…

3 years ago

Gain Practical Expertise with the Latest Edition of Software Architecture with C# 9 and .NET 5

Software architecture is one of the most discussed topics in the software industry today, and…

3 years ago