This tutorial explains step-by-step how to create your own tile editor by using scripts that I've written for the Horn & Tail tile editor.
I think it's a good way to show how to use custom editor scripts with Unity. Similar techniques can be used for lots of other purposes.
If you're a beginner in Unity, you'll learn all the basics about making a custom editor:
This allows you to write some code in any script that's going to be used only in editor mode, and ignored when building a game release.
It can be useful because lots of Unity editor code can't be compiled in release, and will cause errors during the build.
Simple Grid Editor
Let's start with making a very simple version of our tile editor, in which we'll be able to switch on/off some tiles in a predefined size grid.
In order to make it fully functional we'll need:
1. Data structure
First we'll define the data structure for each cell in the grid using a struct. Each GridCell only contains 2 coordinates ( h and v) to define their place in the grid.
I've put the Cell code within the Grid script file, before the Grid class, but it's also allowed to put it in a different file.
Why a struct?
In C#, a struct is generally used for small objects that only hold values. They are treated as value types rather than referenced objects, and it's better for memory and performance in this case.
This attribute at the beginning of the struct will allow unity to save h and v values when these objects are stored in a data structure.
2. Grid Script
This script stores the data structure containing GridCell objects. It's just a list of cells that have been switched on. Switching a cell off is about removing it from the list.
There are actually two data structures, one specific for runtime and one for the editor.
This one is the runtime structure. It uses a generic container that's easy to use and optimized for modifications. It's private so it's not saved in the scene data.
You can see several functions in the script that search for cells, they are used at runtime for various game features.
This one is filled in the editor and saved within the scene. It's using a simple array for this purpose.
We'll see how this data is modified in the next section (Grid editor script).
This attributes forces Unity to save this object within the scene even though it's private and is not saved by default.
It also causes it to be visible and editable in Unity's inspector.
This attributes forces Unity to not show this object in the inspector.
By combining the two previous attributes, you can make hidden saved data.
3. Editor script
This specific editor code in the Grid script is used to edit Cells from user inputs:
This is a custom editor script for Unity:
It has to be placed in a separate file in Assets/Editor folder. This is important because Unity will ignore it when building the game release, and it will avoid getting some errors because of editor specific code.
I've made user inputs this way:
Left click for single cell change.
Right click for press and hold, it will add or remove multiple cells at once when dragging.
It's this way and not all on left click, because drag events on left click are not received properly (I'm assuming it's because of the multiple selection rectangle in Unity scene).
This attribute makes Unity consider this class a custom editor for the given script.
Using the Tile Assets
Now that we have our basic grid editor, let's make different types of tiles to add. We're going to achieve that by instantiating game objects from prefabs instead of just switching some information when you click into the grid.
We'll need four more things:
1. Block script for tile assets
Let's add a short script to be added on all tile assets. Here's the code:
Using this script, we can create tile assets, sprites and anything else we need. We do this by simply adding this script as a component and saving the game object as a prefab.
Its presence in prefabs will help us identify tile assets, and the block type enum will allow us to create different categories, specific to the game.
2. Asset manager script to handle tile assets
This script is searching into a specific folder in order to generate a list of available assets.
One important thing to note is it's using the function Resources.LoadAll<GameObject> in order to enumerate the prefabs. Using this utility requires to put all the prefabs somewhere under Assets/Resources in your project folder.
This attribute forces Unity to execute the script even before the game is started. It allows Start() and Update() functions to be called in the editor.
3. Level editor script
We're adding a new script on the root of the levels being edited. Its purpose is to use the Asset Manager to instantiate a tile in reaction to user inputs in the Grid component.
Again we're using this attribute to force Unity to call Start() in the editor, so we can initialize the Grid component.
As for GridEditor, this is a custom editor script for Unity, it has to be placed in a separate file in Assets/Editor folder. This is important because Unity will ignore it when building the game release, and it will avoid getting some errors because of editor specific code.
Its purpose is to display drop-down lists of available assets (based on AssetManager data) and allow the user to select a tile to create.
4. Modifications in Grid component
Almost everything is setup. The only remaining thing we need is to link the Grid script to Level script, in order to instantiate tile assets when the user clicks in the grid.
For that, we're going to store a Block component inside of each GridCell in the Grid. This will allow us to link our cells with specific tile objects. It's necessary both for the editor (removing a tile) and runtime (check what's on a cell for different purposes).
Here's what it looks like:
And here's how a new helper function to get a Block would look like in Grid:
The GridCell which is passed as a parameter usually doesn't contain a valid block, but only coordinates. You can imagine for example that we're checking cells around the character at runtime. We can create new GridCell with coordinates +/- 1, and use this helper method to check if there's a corresponding block at this position.
Back to the editor, what we need next is to modify our AddCell and RemoveCell methods in Grid script to handle the block.
Here's how adding a cell looks like, now using Level to instantiate the tile asset:
And here's how removing a cell looks like, with just one more line to destroy a previous tile game object:
That's it! We've got a functional tile editor with all basic features.
Advanced Tile Settings
The extra step for our tile editor is the ability to edit tiles with specific settings. I'm going to take an example from our game, but this can be extended to all sorts of features for your own custom editor.
In our case, we needed to connect one tile to another to give players the ability to push a block on Horn's side, and automatically affect a block on Tail's side, and vice versa.
We'll need only one more script:
An editor script on the tile to handle user actions
1. Modify the block script
First we need a small change in the Block script in order to allow a block to be linked to one or several other blocks (for instance the linked blocks are the ones that can be affected when you push the current block).
As described before, this attribute makes the variable to not show up in the editor, while still being saved in the scene.
2. Block editor script
Now here's the new editor script used for linking blocks together:
The user can link block B to block A with these steps:
The user can unlink block B with these steps:
The most interesting part from this script is how to access and modify properties for any component:
This way of making modifications to variables is important, because it will automatically handle several things:
What you've learned
Here are the main things that you've learned in this tutorial:
Hope all of this can be useful to make your own tile editor and lots of other interesting things!
Also if you too have played with custom editors in Unity, don't hesitate to leave comments to share your experience.