Not so fast...

In the previous (actually the first) blog entry, I suggested that there was away around the "no instance data" issue for Unity Tilemaps and that I'd discuss that next. Actually not this time, sorry.

Today I want to talk about how confusing some of the Tilemap nomenclature is.

There's a Tile method called RefreshTile. There's a Tilemap class method called RefreshTile. You'd think that calling Tilemap.RefreshTile would call Tile.RefreshTile. No, it doesn't.

Actually, it calls Tile.GetTileData followed by Tile.StartUp.

What about when you run your Tilemap app in the Editor? All that's called is Tile.Startup. You may well ask, why not Tile.GetTileData too? That's because the tile data is already in the Tilemap component's internal data structures.

It's important to understand that the Tile which is maintained as a reference is only really used for one thing when your app runs: Running StartUp once.

During edit-time, when you paint a tile, GetTileData and GetTileAnimationData are called to load that data (sprite, transform, sprite sequence...) into the internals of the Tilemap instance in the Tilemap component.

When you save the scene, all the data that the various tiles had loaded into the Tilemap component is saved in the scene file in an indexed fashion so that repeated references to the same Tile asset are avoided and so that repeated color, transform, and flags values are also avoided. So at runtime there's no need to call anything other than StartUp; this saves a lot of time when the scene loads when you consider the large number of repeated tiles.

About the only time that I could find Tile.RefreshTile being called is when you're editing Tilemaps and you move the brush around in the Scene or over the Palette area. This makes sense for support of Rule tiles, I suppose; and the Palette is also a Tilemap.

Here's a fun Tile asset that you can add to an empty Unity project. Be sure to use the name 'TestTile.cs' for the filename.

Using the Asset-Create menu, make two of these into Tile assets, add a different sprite to each, drag them into a palette and paint one of each on an empty Tilemap.

You'll see messages in the console when each of these three methods is called with info about whether or not the tile is in the Palette. Drag the Paint tool around on the Tilemap. Click the edit button in the Palette and drag the Paint tool over the palette.

using UnityEngine;
using UnityEngine.Tilemaps;


[CreateAssetMenu(menuName = "Create TestTile", fileName = "TestTile", order = 0)]
public class TestTile : Tile
{
    /// <inheritdoc />
    public override void RefreshTile(Vector3Int position, ITilemap tilemap)
    {
        Debug.Log($"RefreshTile @{position}: from palette? {IsTilemapFromPalette(tilemap)}" );
        base.RefreshTile(position, tilemap);
    }


    /// <inheritdoc />
    public override bool StartUp(Vector3Int position, ITilemap tilemap, GameObject go)
    {
        Debug.Log($"Startup @ {position}: from palette? {IsTilemapFromPalette(tilemap)}");
        return base.StartUp(position, tilemap, go);
    }


    /// <inheritdoc />
    public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
    {
        Debug.Log($"GetTileData @ {position}: from palette? {IsTilemapFromPalette(tilemap)}");
        base.GetTileData(position, tilemap, ref tileData);
    }


    /// <summary>
    /// Is this tilemap actually the palette?
    /// </summary>
    private bool IsTilemapFromPalette(ITilemap iMap)
    {
        var map = iMap.GetComponent<Tilemap>();
        return (map.hideFlags & HideFlags.DontSave) == HideFlags.DontSave;
    }

}