소개

Godot 4는 TileMap 시스템을 완전히 새로 작성했습니다. Godot 3에서 TileMap을 사용해 봤다면 거의 모든 것이 바뀌었습니다 — TileSet 에디터, 타일 정의 방식, 오토 타일링, 레이어, GDScript API까지. 이 가이드는 새로운 아키텍처를 처음부터 설명합니다.

Godot 3 사용자에게: 기존의 autotile, set_cellv(), cell_size는 모두 사라졌습니다. 페이지 하단의 Godot 3에서의 마이그레이션 섹션을 참조하세요.

새로운 TileMap 아키텍처

Godot 4의 TileMap 시스템은 두 가지 주요 구성 요소로 이루어져 있습니다:

  • TileMap 노드 — 씬에 추가하는 노드입니다. 하나 이상의 레이어를 담고 있으며 TileSet 리소스를 참조합니다.
  • TileSet 리소스 — 타일 자체를 정의합니다. 소스(아틀라스, 씬 컬렉션 등), 물리 레이어, 내비게이션 레이어, 커스텀 데이터 레이어, terrain 세트를 포함합니다.

핵심 변경 사항: Godot 3에서는 타일 크기를 TileMap 노드에서 설정했습니다. Godot 4에서는 타일 크기가 TileSet 리소스에 정의되며, TileMap은 그것을 참조하기만 합니다.

TileSet 소스

하나의 TileSet은 여러 개의 소스를 가질 수 있으며, 각 소스는 source_id(정수)로 식별됩니다. 소스 유형은 다음과 같습니다:

  • TileSetAtlasSource — 가장 일반적인 유형입니다. 그리드 형태로 배치된 여러 타일을 담고 있는 하나의 텍스처 이미지입니다.
  • TileSetScenesCollectionSource — 각 타일이 하나의 패킹된 씬입니다. 애니메이션이나 인터랙티브 타일에 유용합니다.

TileSet 설정하기

1단계: TileSet 리소스 만들기

  1. 씬에 TileMap 노드를 추가합니다.
  2. 인스펙터에서 Tile Set 속성을 클릭하고 New TileSet을 선택합니다.
  3. Tile Size를 설정합니다(예: 16x16 또는 32x32).

2단계: 아틀라스 소스 추가하기

  1. TileSet을 클릭하여 하단 패널에서 TileSet 에디터를 엽니다.
  2. + 버튼을 클릭하고 Atlas를 선택합니다.
  3. 타일셋 이미지를 Texture 속성으로 드래그합니다.
  4. 에디터가 타일 크기에 따라 자동으로 타일로 분할합니다. 텍스처 영역과 여백을 조정할 수 있습니다.

3단계: 타일 속성 구성하기

TileSet 에디터에서 모든 타일에 적용되는 다양한 레이어 유형을 추가할 수 있습니다:

  • Physics Layers — 타일의 충돌 형상
  • Navigation Layers — 길찾기용 이동 가능 폴리곤
  • Custom Data Layers — 임의의 타입 지정 데이터(bool, int, float, String 등)
  • Terrain Sets — 오토 타일링용(Godot 3 autotile의 대체)

TileMap 레이어

하나의 TileMap 노드가 여러 레이어를 담을 수 있습니다. 배경과 전경에 각각 별도의 TileMap 노드가 필요했던 Godot 3에 비해 큰 개선점입니다. 각 레이어는 고유한 z-index, y-sort, modulate 설정을 가질 수 있습니다.

일반적인 레이어 구성:

  • Layer 0 — 배경(지면, 바닥) — z-index: -1
  • Layer 1 — 지형(벽, 장애물) — z-index: 0
  • Layer 2 — 전경(플레이어 위에 표시되는 장식) — z-index: 1

레이어용 GDScript API

# Set a cell on layer 0
tilemap.set_cell(0, Vector2i(5, 3), source_id, atlas_coords)

# Get cell info
var source = tilemap.get_cell_source_id(0, Vector2i(5, 3))
var coords = tilemap.get_cell_atlas_coords(0, Vector2i(5, 3))

# Erase a cell
tilemap.erase_cell(0, Vector2i(5, 3))

# Check if a cell is occupied
if tilemap.get_cell_source_id(0, Vector2i(5, 3)) != -1:
    print("Cell has a tile")

API 참고: set_cell()의 첫 번째 매개변수는 항상 레이어 인덱스(0, 1, 2...)입니다. 두 번째는 Vector2i 형식의 셀 위치입니다. 세 번째는 source_id이고, 네 번째는 Vector2i 형식의 atlas_coords입니다.

Terrain 시스템(오토 타일링)

terrain 시스템은 Godot 3의 autotile을 대체합니다. 인접한 타일을 기준으로 올바른 타일 변형을 자동으로 선택합니다.

Terrain 설정하기

  1. TileSet에서 Terrain Set을 추가합니다(인스펙터 → Terrain Sets → Add Element).
  2. terrain 모드를 선택합니다: Match Corners and Sides(47타일), Match Corners(16타일), 또는 Match Sides(16타일).
  3. 세트 안에 terrain 타입을 추가합니다(예: "Grass", "Dirt", "Water").
  4. TileSet 에디터에서 Select 모드로 전환하고, 타일을 선택한 뒤 각 타일에 terrain peering 비트를 페인트합니다.

Terrain 페인트하기

terrain 설정이 끝나면 TileMap 에디터로 전환하여 Terrains 탭을 선택합니다. terrain 타입을 선택하고 맵에 직접 페인트하면, Godot이 자동으로 올바른 타일 변형을 선택합니다.

# Set terrain programmatically
tilemap.set_cells_terrain_connect(0, [Vector2i(5, 3)], 0, 0)
# Parameters: layer, cells array, terrain_set, terrain index

타일의 물리

타일에 충돌을 추가하려면:

  1. TileSet 인스펙터에서 Physics Layer를 추가합니다.
  2. 이 물리 레이어가 사용할 충돌 레이어와 마스크를 설정합니다.
  3. TileSet 에디터에서 Physics 탭으로 전환하여 각 타일에 충돌 폴리곤을 그립니다.

팁: 서로 다른 타일 유형에 대해 여러 개의 물리 레이어를 가질 수 있습니다. 예를 들어 벽용(이동 차단) 레이어 하나와 위험 요소용(Area2D 겹침으로 데미지 트리거) 레이어를 따로 둘 수 있습니다.

타일의 커스텀 데이터

커스텀 데이터 레이어를 사용하면 임의의 타일에 타입 지정 메타데이터를 붙일 수 있습니다. 게임플레이 로직에 매우 유용합니다.

커스텀 데이터 설정하기

  1. TileSet 인스펙터에서 Custom Data Layer를 추가합니다.
  2. 이름을 지정하고(예: "is_destructible") 타입을 설정합니다(예: bool).
  3. TileSet 에디터에서 Custom Data 탭으로 전환하여 타일마다 값을 설정합니다.

코드에서 커스텀 데이터 읽기

var tile_data = tilemap.get_cell_tile_data(0, Vector2i(5, 3))
if tile_data:
    var is_destructible = tile_data.get_custom_data("is_destructible")
    var damage = tile_data.get_custom_data("damage")
    if is_destructible:
        destroy_tile(Vector2i(5, 3))

자주 쓰이는 커스텀 데이터 예시:

  • is_destructible: bool
  • damage: int
  • movement_cost: float
  • tile_type: String (예: "water", "lava", "ice")
  • spawn_chance: float

프로시저럴 타일 배치

새로운 API로 타일을 프로그래밍 방식으로 배치하는 것은 간단합니다:

# Fill a rectangular area
for x in range(20):
    for y in range(10):
        tilemap.set_cell(0, Vector2i(x, y), 0, Vector2i(0, 0))

# Random tile placement
for x in range(50):
    for y in range(50):
        if randf() > 0.7:
            tilemap.set_cell(0, Vector2i(x, y), 0, Vector2i(1, 0))
        else:
            tilemap.set_cell(0, Vector2i(x, y), 0, Vector2i(0, 0))

# Get all used cells on a layer
var used_cells: Array[Vector2i] = tilemap.get_used_cells(0)
print("Layer 0 has ", used_cells.size(), " tiles")

# Clear all tiles on a layer
tilemap.clear_layer(0)

# Clear everything
tilemap.clear()

월드-맵 좌표 변환

# Convert world position to map coordinates
var map_pos: Vector2i = tilemap.local_to_map(world_position)

# Convert map coordinates to world position (center of tile)
var world_pos: Vector2 = tilemap.map_to_local(Vector2i(5, 3))

# Example: check what tile the player is standing on
var player_tile = tilemap.local_to_map(tilemap.to_local(player.global_position))
var tile_data = tilemap.get_cell_tile_data(0, player_tile)
if tile_data:
    var tile_type = tile_data.get_custom_data("tile_type")
    print("Player is on: ", tile_type)

Godot 3에서의 마이그레이션

Godot 3 Godot 4
TileMap.cell_size TileSet.tile_size
set_cellv(pos, tile_id) set_cell(layer, pos, source_id, atlas_coords)
get_cellv(pos) get_cell_source_id(layer, pos)
autotile Terrain 시스템 (Terrain Sets)
TileMap 노드당 단일 레이어 하나의 TileMap에 여러 레이어
TileMap.tile_set = preload(...) TileSet 리소스를 인스펙터 또는 코드로 할당
world_to_map() local_to_map()
map_to_world() map_to_local()

흔한 실수

  1. TileSet을 먼저 만드는 것을 잊는 것. TileSet 리소스를 할당하기 전까지 TileMap 노드는 타일 에디터를 표시하지 않습니다. 인스펙터에서 하나 만드세요.

  2. 잘못된 source_id. 아틀라스 소스가 하나뿐이면 그 source_id0입니다. 두 번째 소스를 추가하면 source_id = 1이 됩니다. TileSet 에디터 하단 패널을 확인하세요 — 각 소스 탭에 ID가 표시됩니다.

  3. atlas_coords와 타일 ID를 혼동하는 것. Godot 4에는 단순한 타일 ID가 없습니다. 대신 아틀라스 그리드 내 위치를 Vector2i(column, row)로 타일을 참조합니다.

  4. 레이어 매개변수를 지정하지 않는 것. 모든 셀 연산은 첫 번째 인자로 레이어 인덱스가 필요합니다. 이를 잊으면 인자 오류가 발생합니다.

  5. set_cellv()를 사용하는 것. 이 메서드는 더 이상 존재하지 않습니다. 새로운 시그니처의 set_cell()을 사용하세요.