TileMapLayer (Godot 4.3+)
Godot 4.3 adicionou o nó TileMapLayer e tornou TileMap obsoleto. Cada TileMapLayer é uma camada, portanto um nível com chão, paredes e decoração usa três nós TileMapLayer irmãos compartilhando um mesmo TileSet. Não escreva código novo contra TileMap, e nunca use a API do Godot 3 (set_cellv, world_to_map, set_cell(x, y, tile_id)).
A API de célula
Uma célula é identificada por coordenadas inteiras do mapa (Vector2i). Um tile é identificado por três valores:
source_id: o ID de uma fonte noTileSet(uma textura de atlas ou uma coleção de cenas). O primeiro atlas geralmente é0; verifique o editor de TileSet ou o valor de retorno deTileSet.add_source().atlas_coords: a coluna e linha do tile dentro desse atlas, em tiles, não em pixels.alternative_tile:0a menos que você tenha criado alternativas espelhadas ou rotacionadas.
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 quando a célula está vazia
var atlas := get_cell_atlas_coords(Vector2i(3, 4)) # Vector2i(-1, -1) quando vazia
print(source_id, atlas)
erase_cell(Vector2i(3, 4))
print(get_used_cells().size(), " células, limites ", 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 retorna o centro da célula no espaço local desta camada.
return to_global(map_to_local(coords))
Fatos importantes:
set_cell(coords)com os argumentos padrão apaga a célula (source_idpadrão é-1). Sempre passesource_ideatlas_coordsao posicionar um tile.- Definir
atlas_coordsque não existem no atlas armazena a célula sem erro (get_cell_source_id()retorna a fonte), eget_cell_tile_data()depois logaThe TileSetAtlasSource atlas has no tile at (x, y).e retornanull. local_to_map()emap_to_local()funcionam no espaço local da camada. Converta comto_local()/to_global()quando a camada for movida ou escalada.get_used_cells_by_id(source_id, atlas_coords)encontra todas as células que usam um tile específico.- As alterações são agrupadas até o final do quadro. Chame
update_internals()se precisar que colisão ou cenas de tiles sejam atualizadas imediatamente.
Dados personalizados por tile
Adicione uma camada de dados personalizados no TileSet (Inspetor > TileSet > Camadas de Dados Personalizados, por exemplo dano do tipo int), pinte valores no editor de TileSet e depois leia-os:
extends TileMapLayer
func dano_em(coords: Vector2i) -> int:
var data := get_cell_tile_data(coords)
if data == null:
return 0
return data.get_custom_data("dano")
get_cell_tile_data() retorna null para células vazias e para tiles de coleção de cenas, portanto verifique antes de chamar métodos nele.
Terrenos (autotiling)
As máscaras de bits de autotile do Godot 3 se tornaram conjuntos de terrenos. No TileSet, adicione um conjunto de terrenos e um terreno, depois pinte os bits de vizinhança de cada tile no editor de TileSet. Em código, passe todas as células que deseja preencher:
extends TileMapLayer
const CONJUNTO_TERRENO := 0
const TERRA := 0
func pintar_sala(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, CONJUNTO_TERRENO, TERRA)
set_cells_terrain_connect() escolhe tiles para que as bordas se conectem; set_cells_terrain_path() é para estradas e rios desenhados como um caminho. Se o resultado mostrar tiles errados ou ausentes, os bits de vizinhança no TileSet estão incompletos; código não pode corrigir isso.
Colisão
Tiles colidem apenas quando o TileSet tem uma camada de física (Inspetor do TileSet > Camadas de Física > Adicionar Elemento) e o tile tem um polígono de colisão nessa camada (editor de TileSet, selecione o tile, Física > Camada de Física 0; pressione F para um retângulo de tile inteiro). A propriedade collision_enabled da camada está ativada por padrão. As camadas de física também carregam collision_layer e collision_mask, definidos no TileSet, não no nó.
Para descobrir qual tile um CharacterBody2D tocou, use o ponto de colisão. get_coords_for_body_rid() retorna as coordenadas de um quadrante de física, não de uma célula, a menos que physics_quadrant_size seja 1 (Godot 4.5+ mescla até 16x16 células em um corpo por padrão):
extends CharacterBody2D
@export var nivel: TileMapLayer
func _physics_process(delta: float) -> void:
velocity += get_gravity() * delta
move_and_slide()
for i in get_slide_collision_count():
var colisao := get_slide_collision(i)
if colisao.get_collider() == nivel:
# Avance levemente para dentro do tile, pois o ponto de contato está na borda.
var dentro := colisao.get_position() - colisao.get_normal()
var coords := nivel.local_to_map(nivel.to_local(dentro))
print("Tocando tile ", coords)
Construindo um TileSet em código
Útil para níveis processuais e para testes que não podem usar o editor de TileSet. Os pontos do polígono de colisão são relativos ao centro do tile.
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))
Migrando do TileMap
No editor: selecione o TileMap, abra o painel inferior TileMap, clique no ícone de caixa de ferramentas e escolha "Extrair camadas do TileMap como nós TileMapLayer individuais". Depois atualize os scripts: todo método de TileMap que recebia um índice de layer vira um método no nó daquela camada, sem o índice.
| Código antigo | 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) |
Erros comuns
- Passar posições em pixels para
set_cell(). Converta comlocal_to_map()primeiro. - Chamar
set_cell(coords, tile_index)com um único número: o segundo argumento é o source ID, eatlas_coordspadrão éVector2i(-1, -1), que apaga a célula. - Esperar colisões de um TileSet que não tem camada de física, ou de tiles sem polígono pintado.
- Usar
get_coords_for_body_rid()com ophysics_quadrant_sizepadrão e obter uma coordenada de quadrante. - Chamar métodos em
get_cell_tile_data()sem verificar se énull. - Adicionar um nó
TileMappara trabalho novo porque tutoriais antigos fazem isso. Use umTileMapLayerpor camada.