Tile Prefabs¶
A tile can carry a prefab that is instantiated wherever the tile is painted: a chest, a torch with a light, a door with its own script. This page covers what the tilemap does with that prefab and how your scripts find out which cell created them.
Concept¶
The prefab is set per tile in the Tile Properties window and
stored in Tile.prefabData, a TilePrefabData. Every time a cell is written with that tile, the
tilemap instantiates the prefab, places it on the cell, and sends the new object the message
OnTilePrefabCreation. Erasing or overwriting the cell destroys the object.
Instances are parented to the tilemap's GameObject, not to a chunk, so you see them in the
hierarchy under the tilemap. In the editor they are created with PrefabUtility.InstantiatePrefab
and keep their prefab link, and painting them is undoable. In a build they are plain
Instantiate copies.
How the instance is placed¶
| Step | Source |
|---|---|
| Position | The centre of the cell, plus offset. With offsetMode set to Pixels the offset is divided by the tileset's pixels per unit; with Units it is used as is. The z comes from the prefab's own position. |
| Rotation | The prefab's local rotation, then rotation as Euler angles. |
| Scale | The prefab's local scale. |
| Tile flags | Rot90 turns the object 90 degrees clockwise about the tilemap's forward axis. FlipH and FlipV together turn it 180 degrees. A single flip negates the scale on that axis. |
The tile itself is not drawn under the prefab unless showTileWithPrefab is set. That is the
Show Tile With Prefab toggle in the Tile Properties window.
Receiving OnTilePrefabCreation¶
Add a method with this signature to a component on the prefab's root GameObject:
The message is sent with SendMessage, which only reaches components on the root, not on
children.
TilemapChunk.OnTilePrefabCreationData carries:
| Member | What it is |
|---|---|
ParentTilemap |
The STETilemap that created the object. |
GridX, GridY |
The cell, in tilemap grid coordinates. |
Tile |
The Tile at that cell. Looked up when you read it. |
Brush |
The TilesetBrush at that cell, or null. |
Parameters |
The brush's parameters if the cell has a brush, otherwise the tile's. May be null. |
An example that reads a tile parameter into the instance:
using UnityEngine;
using CreativeSpore.SuperTilemapEditor;
public class Chest : MonoBehaviour
{
[SerializeField] private int m_gold;
private STETilemap m_tilemap;
private Vector2Int m_cell;
public int Gold => m_gold;
void OnTilePrefabCreation(TilemapChunk.OnTilePrefabCreationData data)
{
m_tilemap = data.ParentTilemap;
m_cell = new Vector2Int(data.GridX, data.GridY);
ParameterContainer parameters = data.Parameters;
if (parameters != null)
m_gold = parameters.GetIntParam("gold", 10);
}
public void Open()
{
// Remove the chest tile. This instance is destroyed at the next rebuild.
m_tilemap.Erase(m_cell.x, m_cell.y);
m_tilemap.UpdateMesh();
}
}
The message can arrive more than once for the same object. Writing the same tile to its cell
again, or calling Refresh with refreshTileObjects set, keeps the existing instance, puts it
back in place and sends the message again. Make the handler safe to repeat.
It is also sent in edit mode while you paint. If your handler must run there, mark the component
[ExecuteAlways], as TileObjectBehaviour is.
TileObjectBehaviour¶
TileObjectBehaviour is a ready-made receiver. Put it on a prefab with a SpriteRenderer, and
when the prefab is created from a tile it sets the renderer's sprite to that tile's image, at the
tilemap's pixels per unit. Unless Change Sprite Only is ticked, it also copies the tilemap's
sorting layer and order in layer.
That turns any tile into a separate GameObject that looks like the tile. One prefab can stand in for every crate, barrel or sign in the tileset, and each instance can have its own collider, rigidbody or script.
OnTilePrefabCreation is protected virtual in TileObjectBehaviour, so you can extend it:
using UnityEngine;
using CreativeSpore.SuperTilemapEditor;
public class BreakableTile : TileObjectBehaviour
{
[SerializeField] private int m_hitPoints = 3;
protected override void OnTilePrefabCreation(TilemapChunk.OnTilePrefabCreationData data)
{
base.OnTilePrefabCreation(data);
m_hitPoints = TilemapUtils.GetTileParameter(data.ParentTilemap, data.GridX, data.GridY, "hitPoints", m_hitPoints);
}
}
For a receiver that is not a TileObjectBehaviour, the static
TileObjectBehaviour.DoOnTilePrefabCreation(data, spriteRenderer, changeSpriteOnly) does the
sprite work for any SpriteRenderer you pass, and TileObjectBehaviour.GetOrCreateSprite(data)
returns the sprite alone. Both cache sprites, one per tile and pixels per unit.
Finding the instance of a cell¶
It returns null when the cell has no prefab instance.
Generating a map with tile prefabs¶
Instances are created inside SetTileData, at the moment of the write, not at the next
rebuild. A generator that writes a cell several times, or clears and regenerates, pays for an
instantiate and a destroy every time. Switch creation off while you generate and create all the
instances once at the end:
STETilemap.DisableTilePrefabCreation = true;
try
{
GenerateLevel(); // your SetTile calls
}
finally
{
STETilemap.DisableTilePrefabCreation = false;
}
// Create the instances for the final map, then rebuild.
tilemap.Refresh(false, false, true, false);
DisableTilePrefabCreation is static and affects every tilemap, which is why the finally
matters. Play mode entry resets it to false.
While it is on, overwriting a cell also leaves its old instance in place. The Refresh call at the
end removes instances whose cell no longer holds a tile with a prefab, and creates the missing
ones.
Destroying is deferred: an object whose cell was overwritten is removed at the next rebuild of
its chunk. ClearMap destroys every child of the tilemap right away, instances included.
Reference¶
TilePrefabData fields, as stored in each Tile:
| Field | What it does |
|---|---|
prefab |
The prefab to instantiate. null means no prefab. |
offset |
Offset from the cell centre. |
offsetMode |
Pixels or Units, the unit of offset. |
rotation |
Extra rotation, in Euler angles. |
showTileWithPrefab |
Draw the tile under the prefab instance too. |
showPrefabPreviewInTilePalette |
Show the prefab's preview in the tile palette instead of the tile. |