TileMapLayer (Godot 4.3+)
Godot 4.3 hat den TileMapLayer-Node hinzugefügt und TileMap als veraltet markiert. Jeder TileMapLayer ist eine Ebene, daher besteht ein Level mit Boden, Wänden und Dekoration aus drei Geschwister-TileMapLayer-Nodes, die sich ein TileSet teilen. Schreiben Sie keinen neuen Code gegen TileMap und verwenden Sie niemals die Godot-3-API (set_cellv, world_to_map, set_cell(x, y, tile_id)).
Die Zellen-API
Eine Zelle wird durch ganzzahlige Kartenkoordinaten (Vector2i) identifiziert. Eine Kachel wird durch drei Werte identifiziert:
source_id: Die ID einer Quelle imTileSet(eine Atlas-Textur oder eine Szenen-Sammlung). Der erste Atlas ist normalerweise0; überprüfen Sie den TileSet-Editor oder den Rückgabewert vonTileSet.add_source().atlas_coords: Die Spalte und Zeile der Kachel innerhalb dieses Atlas, in Kacheln, nicht in Pixeln.alternative_tile:0, es sei denn, Sie haben gespiegelte oder gedrehte Alternativen erstellt.
extends TileMapLayer
const SOURCE_ID := 0
const GRASS := Vector2i(0, 0)
const WALL := Vector2i(1, 0)
func _ready() -> void:
for x in range(10):
set_cell(Vector2i(x, 5), SOURCE_ID, GRASS)
set_cell(Vector2i(3, 4), SOURCE_ID, WALL)
var source_id := get_cell_source_id(Vector2i(3, 4)) # -1 wenn die Zelle leer ist
var atlas := get_cell_atlas_coords(Vector2i(3, 4)) # Vector2i(-1, -1) wenn leer
print(source_id, atlas)
erase_cell(Vector2i(3, 4))
print(get_used_cells().size(), " Zellen, Grenzen ", get_used_rect())
func cell_at_global(global_point: Vector2) -> Vector2i:
return local_to_map(to_local(global_point))
func center_of_cell(coords: Vector2i) -> Vector2:
# map_to_local gibt den Zellenmittelpunkt im lokalen Raum dieser Ebene zurück.
return to_global(map_to_local(coords))
Wichtige Fakten:
set_cell(coords)mit den Standardargumenten löscht die Zelle (source_idstandardmäßig-1). Übergeben Sie immersource_idundatlas_coords, wenn Sie eine Kachel platzieren.- Das Setzen von
atlas_coords, die im Atlas nicht existieren, speichert die Zelle ohne Fehler (get_cell_source_id()gibt die Quelle zurück), undget_cell_tile_data()protokolliert späterThe TileSetAtlasSource atlas has no tile at (x, y).und gibtnullzurück. local_to_map()undmap_to_local()arbeiten im lokalen Raum der Ebene. Konvertieren Sie mitto_local()/to_global(), wenn die Ebene verschoben oder skaliert wurde.get_used_cells_by_id(source_id, atlas_coords)findet jede Zelle, die eine bestimmte Kachel verwendet.- Änderungen werden bis zum Ende des Frames gesammelt. Rufen Sie
update_internals()auf, wenn Kollisionen oder Szenen-Kacheln sofort aktualisiert werden müssen.
Benutzerdefinierte Daten pro Kachel
Fügen Sie eine benutzerdefinierte Datenebene im TileSet hinzu (Inspektor > TileSet > Custom Data Layers, z. B. damage vom Typ int), malen Sie Werte im TileSet-Editor und lesen Sie sie dann aus:
extends TileMapLayer
func damage_at(coords: Vector2i) -> int:
var data := get_cell_tile_data(coords)
if data == null:
return 0
return data.get_custom_data("damage")
get_cell_tile_data() gibt null für leere Zellen und für Szenen-Sammlungs-Kacheln zurück, prüfen Sie daher vor dem Aufruf von Methoden darauf.
Terrains (Autotiling)
Godot-3-Autotile-Bitmasken wurden zu Terrain-Sets. Fügen Sie im TileSet ein Terrain-Set und ein Terrain hinzu, malen Sie dann die Terrain-Nachbarschaftsbits jeder Kachel im TileSet-Editor. Übergeben Sie im Code jede Zelle, die Sie füllen möchten:
extends TileMapLayer
const TERRAIN_SET := 0
const DIRT := 0
func paint_room(rect: Rect2i) -> void:
var cells: Array[Vector2i] = []
for x in range(rect.position.x, rect.end.x):
for y in range(rect.position.y, rect.end.y):
cells.append(Vector2i(x, y))
set_cells_terrain_connect(cells, TERRAIN_SET, DIRT)
set_cells_terrain_connect() wählt Kacheln so aus, dass die Kanten verbunden sind; set_cells_terrain_path() ist für als Pfad gezeichnete Straßen und Flüsse gedacht. Wenn das Ergebnis falsche oder fehlende Kacheln zeigt, sind die Nachbarschaftsbits im TileSet unvollständig; Code kann das nicht beheben.
Kollision
Kacheln kollidieren nur, wenn das TileSet einen Physik-Layer hat (TileSet-Inspektor > Physics Layers > Add Element) und die Kachel ein Kollisionspolygon auf diesem Layer hat (TileSet-Editor, Kachel auswählen, Physics > Physics Layer 0; F drücken für ein Vollkachel-Rechteck). Die Eigenschaft collision_enabled des Layers ist standardmäßig aktiviert. Physik-Layer haben auch collision_layer und collision_mask, die auf dem TileSet gesetzt werden, nicht auf dem Node.
Um herauszufinden, welche Kachel ein CharacterBody2D berührt hat, verwenden Sie den Kollisionspunkt. get_coords_for_body_rid() gibt die Koordinaten eines Physik-Quadranten zurück, nicht einer Zelle, es sei denn, physics_quadrant_size ist 1 (Godot 4.5+ fasst standardmäßig bis zu 16 x 16 Zellen zu einem Body zusammen):
extends CharacterBody2D
@export var level: TileMapLayer
func _physics_process(delta: float) -> void:
velocity += get_gravity() * delta
move_and_slide()
for i in get_slide_collision_count():
var collision := get_slide_collision(i)
if collision.get_collider() == level:
# Treten Sie leicht in die Kachel, da der Kontaktpunkt auf ihrer Kante liegt.
var inside := collision.get_position() - collision.get_normal()
var coords := level.local_to_map(level.to_local(inside))
print("Berührt Kachel ", coords)
Erstellen eines TileSets in Code
Nützlich für prozedurale Levels und für Tests, die den TileSet-Editor nicht verwenden können. Kollisionspolygonpunkte sind relativ zum Kachelmittelpunkt.
extends Node2D
func _ready() -> void:
var tile_set := TileSet.new()
tile_set.tile_size = Vector2i(16, 16)
tile_set.add_physics_layer()
var source := TileSetAtlasSource.new()
source.texture = load("res://tiles.png") as Texture2D
source.texture_region_size = Vector2i(16, 16)
source.create_tile(Vector2i(0, 0))
var source_id := tile_set.add_source(source)
var data := source.get_tile_data(Vector2i(0, 0), 0)
data.add_collision_polygon(0)
data.set_collision_polygon_points(0, 0, PackedVector2Array([
Vector2(-8, -8), Vector2(8, -8), Vector2(8, 8), Vector2(-8, 8),
]))
var layer := TileMapLayer.new()
layer.tile_set = tile_set
add_child(layer)
layer.set_cell(Vector2i(0, 0), source_id, Vector2i(0, 0))
Migration von TileMap
Im Editor: Wählen Sie die TileMap, öffnen Sie das TileMap-Unterpanel, klicken Sie auf das Werkzeugkasten-Symbol und wählen Sie „Extract TileMap layers as individual TileMapLayer nodes“. Aktualisieren Sie dann die Skripte: Jede TileMap-Methode, die zuerst einen layer-Index akzeptierte, wird zu einer Methode auf dem Node dieser Ebene, ohne den Index.
| Alter Code | TileMapLayer |
|---|---|
tile_map.set_cell(0, coords, source_id, atlas_coords) | ground.set_cell(coords, source_id, atlas_coords) |
tile_map.get_cell_source_id(1, coords) | walls.get_cell_source_id(coords) |
tile_map.get_used_cells(0) | ground.get_used_cells() |
tile_map.set_layer_enabled(2, false) | decoration.enabled = false |
tile_map.set_layer_z_index(1, 5) | walls.z_index = 5 |
Godot 3 set_cellv(pos, id), world_to_map(p), map_to_world(c) | set_cell(coords, source_id, atlas_coords), local_to_map(p), map_to_local(c) |
Häufige Fehler
- Pixelpositionen an
set_cell()übergeben. Zuerst mitlocal_to_map()konvertieren. set_cell(coords, tile_index)mit einer Zahl aufrufen: Das zweite Argument ist die Quell-ID, undatlas_coordsstandardmäßigVector2i(-1, -1), was die Zelle löscht.- Kollisionen von einem TileSet erwarten, das keinen Physik-Layer hat, oder von Kacheln ohne gezeichnetes Polygon.
get_coords_for_body_rid()mit der standardmäßigenphysics_quadrant_sizeverwenden und eine Quadrantenkoordinate erhalten.- Methoden auf
get_cell_tile_data()aufrufen, ohne aufnullzu prüfen. - Einen
TileMap-Node für neue Arbeiten hinzufügen, weil ältere Tutorials das tun. Verwenden Sie einenTileMapLayerpro Ebene.