1
\$\begingroup\$

I'm building a 2D strategy game where I've decided to use TileMap for spaces which characters can traverse. My tiles need to be prefabs, because they will have a script attached to them to store things like their type, cost, any effects they might have on them, name, etc.

To build the TileMap I imported Unity 2D Extras and used its prefab brush. I've actually tried this a couple of ways. First I just manually placed the prefabs and dragged them into the hierarchy under GameTileMap. When that didn't work I thought maybe I needed to do it with the prefab brush so I deleted everything and did the whole thing again that way. Still nothing.

Here is how my Hierarchy looks:

enter image description here

And this is the code I used to try and get that list of all the Tile prefabs I have there:

using UnityEngine.Tilemaps;
using UnityEngine;

public class TileManager : MonoBehaviour {

  public static TileManager instance;
  public Tilemap Tilemap;

  void Awake() {
    if (instance == null) {
      instance = this;
    }
    else if (instance != this) {
      Destroy(gameObject);
    }

    // Do I even have any tiles?
    TileBase[] allTiles = Tilemap.GetTilesBlock(Tilemap.cellBounds);

    // Print positions of each tile if I have any.
    foreach (Vector3Int pos in Tilemap.cellBounds.allPositionsWithin) {
      var localPlace = new Vector3Int(pos.x, pos.y, pos.z);
      Debug.Log(localPlace);
    }

  }
}

The above code is on my TileManager. When run, allTiles list is empty so of course no Debug output is logged.

Question:

Is it possible to get list of tiles that have been painted with the prefab brush?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

So to recap:

Initial Problem

  • Desire to create a tile map using the TileMap feature with 2d-extras
  • Above mentioned tiles should be able to store data about themselves. Data like cost, type, etc.
  • Must be able to be referenced in code. i.e read them in from the tile map

Round Peg Square Hole

  • Attempted to create these tiles as prefabs.
  • Created scripts to attach to each prefab that would store said data
  • Attempted to use the prefab brush to paint these tiles as prefabs with the expectation that I could get them from the tilemap in code.

Results

  • Prefabs were not added as part of the tilemap

Correct Solution

  • Scriptable tiles solved all initial problems

The way this works is you create an editor script call <MyTileType>, in my case TerrainTile. This script is going to add an option in your Assets/Create menu that will have the name you choose and that will create a .asset file with that name.

.asset files can be dragged into the tile palette. Your class will inherit from UnityEngine.Tilemaps.TileBase and in there you can store w/e data you want. Once you have this, the world is yours.

Links that lead me to victory

Some things that weren't immediately obvious if you've never written any editor scripts before

  • I needed to set my sprite import settings for my terrain asset's PPU to match the file size (in my case 1024 x 1024) so that it scaled perfectly to my grid.
  • Class structure needs to be like:
#if UNITY_EDITOR
using UnityEditor;
#endif

public class TerrainTile : TileBase
{
  // W/e fields you want.
  [SerializeField]
  private Sprite[] _sprite = default;

  [SerializeField]
  private int _cost = 0;

// Must be inside the class you're trying to use
---------------------------------------------------
#if UNITY_EDITOR
  // The following is a helper that adds a menu item to create a MyTile Asset
  [MenuItem("Assets/Create/TerrainTile")]
  public static void CreateTerrainTile() {
    string path = EditorUtility.SaveFilePanelInProject("Save Terrain Tile", "New Terrain Tile", "Asset", "Save Terrain Tile", "Assets");
    if (path == "")
      return;
    AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<TerrainTile>(), path);
  }
#endif
---------------------------------------------------

  public override void RefreshTile(Vector3Int position, ITilemap tilemap) {
    // Read docs for an explanation on this.
    tilemap.RefreshTile(position);
  }

  public override void GetTileData(Vector3Int position, ITilemap tileMap, ref UnityEngine.Tilemaps.TileData tileData) {

    // This is for the preview in the tile palette.
    tileData.sprite = _sprite[0];
  }
}

Its clear that the prefab brush was not built for this. It seems intended to be used to simply paint sparsely used prefabs such as items, scenery, etc.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .