Wie bekomme ich alle Kacheln von einer Tilemap?

13

Ich habe das neue TileMapSystem in Unity ein wenig ausprobiert und nach einer Möglichkeit gesucht, auf die Kacheln als Liste oder 2D-Array zuzugreifen, aber ich kann nichts anderes finden, als GetTile(Vector3Int vector)nur eine Kachel zurückzugeben ... Gibt es eine Möglichkeit? um dies zu tun ?

Shashimee
quelle

Antworten:

18

Verwenden Sie, um ein Array mit allen Kacheln aus einem rechteckigen Bereich Ihrer Kachelkarte zu erhalten tilemap.GetTilesBlock(BoundsInt bounds). Sie erhalten eine eindimensionale Anordnung von Kacheln, sodass Sie selbst wissen müssen, wann die nächste Kachelreihe beginnt. Alle leeren Zellen werden mit einem nullWert dargestellt.

Wenn Sie alle Kacheln möchten , verwenden Sie tilemap.cellBounds. Dadurch erhalten Sie ein BoundsIntObjekt, das den gesamten verwendeten Bereich der Tilemap abdeckt. Hier ist ein Beispielskript, das alle Kacheln aus der Tilemap auf demselben Spielobjekt abruft und die Kacheln mit ihren Koordinaten auflistet:

using UnityEngine;
using UnityEngine.Tilemaps;

public class TileTest : MonoBehaviour {
    void Start () {
        Tilemap tilemap = GetComponent<Tilemap>();

        BoundsInt bounds = tilemap.cellBounds;
        TileBase[] allTiles = tilemap.GetTilesBlock(bounds);

        for (int x = 0; x < bounds.size.x; x++) {
            for (int y = 0; y < bounds.size.y; y++) {
                TileBase tile = allTiles[x + y * bounds.size.x];
                if (tile != null) {
                    Debug.Log("x:" + x + " y:" + y + " tile:" + tile.name);
                } else {
                    Debug.Log("x:" + x + " y:" + y + " tile: (null)");
                }
            }
        }        
    }   
}

In Bezug auf die Grenzen und warum Sie möglicherweise mehr Kacheln erhalten als erwartet: Konzeptionell haben Unity Tilemaps eine unbegrenzte Größe. DascellBounds wachsen nach Bedarf, wenn Sie Fliesen bemalen, aber sie schrumpfen nicht wieder, wenn Sie sie löschen. Wenn Ihr Spiel eine genau definierte Kartengröße hat, können Sie einige Überraschungen erleben, wenn Sie beim Bearbeiten von Karten jemals ausrutschen. Es gibt drei Möglichkeiten, um dieses Problem zu umgehen:

  • Anruf tilemap.CompressBounds() an, um die Grenzen der äußersten Kacheln wiederherzustellen (in der Hoffnung, dass Sie daran gedacht haben, sie zu löschen)
  • Erstellen Sie das boundsObjekt selbst, new BoundsInt(origin, size)anstatt sich darauf zu verlassencellBounds .
  • setze tilemap.originund tilemap.sizeauf die gewünschten Werte und rufe dann auf tilemap.ResizeBounds().
Philipp
quelle
11

Hier ist eine andere Möglichkeit, dies zu tun .cellBounds.allPositionsWithin

public Tilemap tilemap;
public List<Vector3> tileWorldLocations;

// Use this for initialization
void Start () {
    tileWorldLocations = new List<Vector3>();

    foreach (var pos in tilemap.cellBounds.allPositionsWithin)
    {   
        Vector3Int localPlace = new Vector3Int(pos.x, pos.y, pos.z);
        Vector3 place = tilemap.CellToWorld(localPlace);
        if (tilemap.HasTile(localPlace))
        {
            tileWorldLocations.Add(place);
        }
    }

    print(tileWorldLocations);
}
Allencodiert
quelle
2

Während ich herausfinde, wie man alle benutzerdefinierten Kacheln von Tilemap erhält und aufgrund der in den Antworten erwähnten Methode ITilemapkeine hat, GetTilesBlockschlage ich vor, eine Erweiterungsmethode wie diese hinzuzufügen (nur 2D):

public static class TilemapExtensions
{
    public static T[] GetTiles<T>(this Tilemap tilemap) where T : TileBase
    {
        List<T> tiles = new List<T>();

        for (int y = tilemap.origin.y; y < (tilemap.origin.y + tilemap.size.y); y++)
        {
            for (int x = tilemap.origin.x; x < (tilemap.origin.x + tilemap.size.x); x++)
            {
                T tile = tilemap.GetTile<T>(new Vector3Int(x, y, 0));
                if (tile != null)
                {
                    tiles.Add(tile);
                }
            }
        }
        return tiles.ToArray();
    }
}

Wenn Sie in diesem Fall eine benutzerdefinierte Kachel TileRoad haben, die von Tile oder TileBase geerbt wurde, können Sie alle TileRoad-Kacheln mit folgendem Aufruf abrufen:

TileBase[] = tilemap.GetTiles<RoadTile>();

Für ITilemap können wir den Parameter (this Tilemap tilemap)in ändern , (this ITilemap tilemap)aber das habe ich nicht überprüft.

Dmitry Tabakov
quelle
In welcher Situation müssen Sie mit der ITilemap-Schnittstelle umgehen? Ich bin bei meinen Experimenten mit dem Tilemap-System überhaupt nicht darauf gestoßen. Ich habe immer die Tilemap-Komponente mit erworben GetComponent<Tilemap>().
Philipp
~ Philipp, kann nichts über die Benutzeroberfläche sagen, da ich auch nur mit Component gearbeitet habe.
Dmitry Tabakov