TilePlus and Prefabs

If you're a Unity3D dev you're familiar with prefabs. What is a prefab exactly?

A prefab is not unlike a scene file with the major difference being that scene references are lost. Here's a simple example:

This is the scene:

SimplePrefabExample.png

Note that the Test script has a field called ReferenceToSceneObject. That's setup to reference the GameObject called SceneGameObject.

Here's what the Test script component looks like in the scene file:

MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 8134853141899817304}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: f03a015a208c36a48901e47762c633c5, type: 3}
  m_Name: 
  m_EditorClassIdentifier: 
  m_ReferenceToSceneObject: {fileID: 132779707}

As you can see, the very last line holds the reference. After creating a prefab of GameObjectForPrefab we can look at the prefab file.

MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 6779053189875886357}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: f03a015a208c36a48901e47762c633c5, type: 3}
  m_Name: 
  m_EditorClassIdentifier: 
  m_ReferenceToSceneObject: {fileID: 0}

Whoops! No more reference to the scene object.

This is exactly how it's supposed to work! Imagine if the prefab had maintained a reference to the scene object but you loaded this prefab into a scene without the scene object. Null-reference exception? Crash? Who knows. But it would be wrong.

This creates a problem for TilePlus tiles since they're scene objects. If you create a prefab out of a Grid+Tilemap with these new tiles, instantiating the prefab creates the famous "pink tiles" display.

But prefabs are pretty useful. Briefly, the solution involves creating a prefab programmatically and not allowing the user to create a prefab which has a TilePlus tile in it.

How do you stop a user from creating a prefab? It's actually pretty easy: just hook into the editor callback PrefabUtility.prefabInstanceUpdated and (simplified) if any TilePlus tiles exist on that map revert the prefab instance. This won't affect any other type of prefab creation.

How do you create a custom prefab? It's not unlike creating any other asset, although the code is a bit involved. Interested readers can peruse Plugins/TilePlus/Editor/StaticLib/TpPrefabUtilities.cs.

The interesting part of the process involves properly archiving the TilePlus tiles. Simply, a tilemap archive asset is created for each tilemap with the TilePlus tiles as sub-assets.

Similar to what you'd see in the scene file for a tilemap, lookup tables are used to save space for the oft-repeated values such as transform, color, and so on. In essence, it's a custom scene format for tilemaps that avoids the limitations of tilemap data storage in a standard Unity scene file.

One extra new asset is also created: a TileFab. This is a master asset which refers to all the tilemap archives. Hence, if you archive a Grid with, say, three child tilemaps then the Tilefab has references to all three archives. What's this for?

TileFabs can be easily loaded into position in an existing tilemap. For the example of a grid with three child tilemaps, the tiles from all three tilemaps can be loaded into an existing map at the same time with any Vector3Int offset that you like.

This allows dynamic loading during gameplay. You can see this in operation in the TopDownDemo, and it uses a TpLib method called LoadImportedTileFab.

Also provided is TpLoader, a Monobehaviour component which can have a reference to a tilemap archive asset (as opposed to a TileFab) in the Project folder. Attached to the same GameObject as a tilemap component, this script can be used to load the archive to the tilemap when the scene is loaded or at any other time.