How to have instanced Tile data

How to have instanced Tile data

In an earlier post I mentioned that it is possible to have instanced Tile data when using Unity Tilemaps. It's been a while, but now that I've uploaded the TilePlus Toolkit asset to the Unity Asset store, it's a good time for me to STOP CODING and talk about how it's done.

Simply put, make a clone of the tile after it's painted. Sounds easy! Uh, not really.

Perhaps it might help to explain why I did this at all.

I've been working on a casual games project using Unity3D. As a Unity user since about 2009, my first sensation when Tilemaps were added to Unity in 2017.2 was "Wow! Tilemaps!!". Soon replaced by "you mean tiles can't have instance data? WTF!".

I first used the Tiled tilemap editor to create tilemaps and import them using the Tiled TMX Importer from the Asset Store (from Gaming Garrison). But I really wanted to work within the Editor itself: Every change that I made required an import process and some manual adjustments. Besides, I ended up having instance data in prefabs, which is really annoying from a design point of view. I really wanted to have intelligent tiles.

I wanted tiles that could react to the environment and have better animation capabilities than the animated tiles from 2D Tilemap Extras.

So it became a challenge to figure out why Tiles can't have instance data. As I talked about in an earlier post, you can examine Unity's text-mode YAML scene files to infer that tiles are mostly used to set up lookup tables and such within the C++ engine code that comprises the engine's tilemap implementation. As such, all that is saved in the scene file is a set of lookup tables for transform, color, and flags, and a reference to the tile asset. At runtime (Play mode), the tile asset isn't really used for much after it's StartUp method is called.

But if one clones the tile asset using Instantiate then you have a "floating" copy of the tile, which is really just a Scriptable Object subclass.

If you use that copy when calling Tilemap.SetTile, the copy becomes bound to the Tilemap due to the reference which the Tilemap maintains. It really isn't a big deal to have a Scriptable Object reference in the scene hierarchy: it doesn't appear in the editor; but more importantly, it's saved with the scene. In effect, it's now a "transformless" GameObject.

About the only downside to this is that since these are scene objects, and since the tilemap's internal reference is to a TileBase (among other issues), if you do a simple drag-drop of a tilemap to make a prefab in a project folder, the connection is lost. There are several ways to handle this, but I chose to code a custom prefab creator.

However, there are other ways to load tilemaps dynamically. That's the topic of an upcoming post.