Tilemap Nirvana
For the last few years I've been working on a framework for casual games using the Unity game engine. Using native Unity Tilemaps is efficient, but very limiting. This is because they're designed for display efficiency but there's no apparent way to add custom data to tiles. It's just not stored anywhere.
I decided to jump down the rabbit hole and figure out why.
The answer can be found by creating a simple scene with a Tilemap and a few tiles. If you ensure that asset serialization is set to force text, then saving the scene gives you something to look at. Here's the most interesting part - the internals of the entry for the Tilemap component. Here's the serialized data for a single tile:
- first: {x: -4, y: 1, z: 0}
second:
serializedVersion: 2
m_TileIndex: 4
m_TileSpriteIndex: 0
m_TileMatrixIndex: 0
m_TileColorIndex: 0
What's going on here? The line first: {x: -4, y: 1, z: 0}
tells us the grid position of the tile i.e., where it is on the Tilemap. But what's the rest of this about? What are the indexes for?
Looking elsewhere in the file one finds this:
m_TileAssetArray:
- m_RefCount: 1
m_Data: {fileID: 206097775}
- m_RefCount: 1
m_Data: {fileID: 619153061}
- m_RefCount: 0
m_Data: {fileID: 0}
- m_RefCount: 1
m_Data: {fileID: 1263359791}
- m_RefCount: 1
m_Data: {fileID: 1690371934}
- m_RefCount: 1
m_Data: {fileID: 1056322544}
- m_RefCount: 1
m_Data: {fileID: 1174581608}
- m_RefCount: 1
m_Data: {fileID: 1667070803}
- m_RefCount: 1
m_Data: {fileID: 628196556}
Ah, so the indexes point into a lookup table of tile assets! The fileID's must map to actual tile assets in the Project folder somewhere. Other lookup tables for the sprites, colors, etc can also be found.
The intent here seems clear: Tilemaps are for displaying visual information and that's all. Since there's so much repetition of individual tiles it makes a lot of sense to use lookup tables to reduce the amount of data to serialize.
If you've ever worked with Unity tilemaps you might have attempted to add some fields to a subclass of Tile, let's say some sort of boolean value to control something. It seems to work! But then you paint a second instance of your fancy new tile. You change the bool's value, and lo and behold you find that the value of this variable in the first tile that you had painted, and indeed, the value of the bool itself in the actual tile asset has also changed.
Hard stop! It doesn't work.
Actually it's almost impossible to do the steps I've just outlined. When you paint the tile you can select it with the brush and view its values in the selection inspector.
But that will only display the standard tile fields like color and so on. If you have Odin Inspector installed you can open an inspector on the tile right from the brush's selection inspector, twiddle the new fields and you'll see what I just described.
But this is not news to the Unity development community.
One way to add functionality to tiles is to add a prefab to the tile, and it will create an instance of the prefab for you. This isn't terribly useful (IMO) since it's the same prefab each time.
In the next post I'll talk about how I found a way to get around all this.