20강타일맵과 레벨 제작
TileMapLayer, 오토타일, 충돌 타일.
이 강의 목차 (8)
- 타일셋을 만들고
TileMapLayer로 맵을 그린다. - 타일에 충돌을 붙인다.
- 오토타일(터레인)로 벽 모서리를 자동 처리한다.
왜 타일맵인가#
스테이지를 Sprite2D 수백 개로 만들면 이렇게 됩니다.
- 씬 파일이 거대해지고 에디터가 느려짐
- 벽 하나하나에 콜라이더를 붙여야 함
- 드로우 콜이 수백 개 (6강)
- 맵을 고치려면 노드를 일일이 옮겨야 함
타일맵은 이 전부를 해결합니다.
격자를 정해두고, 각 칸에 "몇 번 타일" 인지 숫자만 기록하는 방식.
- 데이터가 작음 (좌표 + 타일 번호)
- 한 번에 그려짐 (같은 텍스처라 배칭이 완벽)
- 충돌도 타일 단위로 자동 생성
- 붓처럼 칠해서 편집
- Godot 4.0~4.2:
TileMap노드 하나가 여러 레이어를 가짐 - Godot 4.3+:
TileMapLayer노드가 레이어 하나씩을 담당
새 프로젝트는 TileMapLayer를 쓰세요. 옛날 튜토리얼은 TileMap 기준이라 화면이 다릅니다.
TileMap 노드를 선택하면 TileMapLayer들로 자동 변환하는 버튼이 나옵니다.
1) 타일셋 만들기#
타일셋(TileSet) 은 "쓸 수 있는 타일들의 목록"입니다.
TileMapLayer노드 추가- 인스펙터의
Tile Set→New TileSet - 하단 TileSet 패널이 열림
- 좌하단
+로 아틀라스 추가 → 타일 이미지(.png) 지정 - 타일 크기 지정 (예: 16×16, 32×32)
- "타일을 자동으로 만들까요?" → 예
| 크기 | 특징 |
|---|---|
| 8×8 | 아주 세밀. 파일이 많아짐 |
| 16×16 | 픽셀아트 표준 |
| 32×32 | 픽셀아트~일반 |
| 64×64 이상 | 고해상도 아트 |
한 번 정하면 바꾸기 매우 어렵습니다. 15강의 기준 해상도와 함께 초기에 결정하세요.
2) 맵 그리기#
TileMapLayer 노드를 선택하면 하단에 TileMap 패널이 나옵니다.
| 도구 | 단축키 | 하는 일 |
|---|---|---|
| 그리기 | D |
붓으로 칠하기 |
| 지우기 | E |
지우기 |
| 선택 | S |
영역 선택 후 복사 |
| 채우기 | B |
페인트 통 |
| 사각형 | R |
사각형 영역 채우기 |
| 스포이드 | P |
이미 놓인 타일 집기 |
Shift를 누르고 드래그하면 직선, Ctrl을 누르면 지우기로 전환됩니다.
3) 충돌 붙이기#
이게 타일맵의 진짜 힘입니다.
- TileSet 패널 → 좌측
물리 레이어(Physics Layers)→+로 레이어 추가 - 레이어의
Collision Layer를world(1번)로 설정 (11강) - 상단 탭을
선택(Select)으로 바꾸고 타일 하나를 클릭 - 좌측 속성에서
Physics → Polygon항목의 편집기를 열어 타일 위에 다각형을 그림 - 사각형 타일이면 "사각형 자동 생성" 버튼 한 번이면 끝
타일을 칠하기만 하면 그 자리에 콜라이더가 자동으로 생깁니다.
StaticBody2D를 하나도 안 만들었는데 캐릭터가 벽에 막힙니다.
여러 타일이 붙어 있으면 엔진이 하나의 큰 콜라이더로 합쳐줍니다. 성능상으로도 유리합니다.
디버그 → 충돌 도형 표시를 켜고 실행하세요.
칠한 벽 타일에만 파란 윤곽이 보이면 성공입니다.
4) 터레인(오토타일) — 모서리 자동 처리#
벽을 그릴 때 가장 귀찮은 게 모서리와 가장자리입니다. 왼쪽 끝, 오른쪽 끝, 안쪽 모서리, 바깥 모서리… 종류가 십수 개입니다.
터레인(Terrain) 을 설정하면 주변 타일을 보고 알맞은 모양을 자동 선택합니다.
- TileSet 패널 →
터레인 세트(Terrain Sets)→+ - 모드를
Match Corners and Sides로 설정 - 터레인 하나 추가하고 이름을
땅으로 선택탭에서 각 타일을 고르고Terrains → Terrain항목에서 그 타일의 어느 부분이 땅인지 페인트로 칠함- TileMap 패널의
Terrains탭에서 그리면 자동으로 모양이 결정됨
타일 47종의 터레인 비트를 칠하는 데 20~30분쯤 걸립니다. 하지만 그 뒤로는 맵을 그리는 시간이 5배 빨라집니다. 스테이지가 2개 이상이면 반드시 이깁니다.
여러 레이어로 나누기#
한 화면에 여러 TileMapLayer를 겹칩니다.
World (Node2D) Y Sort Enabled
├─ Background (TileMapLayer) z_index -10, 충돌 없음
├─ Ground (TileMapLayer) z_index 0, 충돌 있음
├─ Decoration (TileMapLayer) z_index 5, 충돌 없음
├─ Player
├─ Enemies
└─ Foreground (TileMapLayer) z_index 20, 캐릭터를 가림| 레이어 | 용도 |
|---|---|
| Background | 하늘, 먼 배경 |
| Ground | 바닥과 벽 (충돌) |
| Decoration | 풀, 돌, 균열 |
| Foreground | 캐릭터 앞을 가리는 나뭇잎, 지붕 |
코드에서 타일 다루기#
extends TileMapLayer
func _ready() -> void:
# 타일 좌표 (3, 5)에 아틀라스 (0,0) 타일 놓기
set_cell(Vector2i(3, 5), 0, Vector2i(0, 0))
# 지우기
erase_cell(Vector2i(3, 5))
# 그 칸에 뭐가 있는지
var src := get_cell_source_id(Vector2i(3, 5))
if src == -1:
print("빈 칸")
# 픽셀 좌표 ↔ 타일 좌표 변환
func world_to_tile(p: Vector2) -> Vector2i:
return local_to_map(to_local(p))
func tile_to_world(t: Vector2i) -> Vector2:
return to_global(map_to_local(t))- 타일 좌표
Vector2i(3, 5)— 격자 칸 번호 - 월드 좌표
Vector2(96, 160)— 픽셀 위치
local_to_map() / map_to_local() 이 둘을 오갑니다.
map_to_local()은 타일의 중심점을 돌려줍니다. 이걸 몰라서 반 칸씩 어긋나는 일이 흔합니다.
커스텀 데이터 레이어 — 타일에 정보 붙이기
"이 타일은 물이라 느려진다", "이 타일은 용암이라 데미지"를 표현하려면 커스텀 데이터 레이어를 씁니다.
- TileSet 패널 →
커스텀 데이터 레이어→+ - 이름
speed_mul, 타입float로 추가 - 각 타일을 선택해 값 지정 (물 타일 = 0.5)
func speed_multiplier_at(pos: Vector2) -> float:
var cell := local_to_map(to_local(pos))
var d := get_cell_tile_data(cell)
if d == null:
return 1.0
return d.get_custom_data("speed_mul")이렇게 하면 타일 하나하나가 게임 규칙을 가집니다. 19강의 데이터 주도 설계가 타일에도 적용되는 셈입니다.
실습 — 스테이지 한 판#
- 16×16 타일셋을 만들고 바닥·벽 타일에 충돌을 붙입니다.
TileMapLayer레이어를 3개(Background / Ground / Decoration) 만듭니다.- 가로 60칸, 세로 34칸 정도의 방을 하나 그립니다.
- 9강의 플레이어와 19강의 적을 배치합니다.
- 14강의 카메라 리미트를 맵 크기에 맞춰 설정합니다.
# 타일맵 크기에서 카메라 리미트를 자동 계산
func fit_camera_to_map(map: TileMapLayer, cam: Camera2D) -> void:
var used := map.get_used_rect()
var cell := Vector2(map.tile_set.tile_size)
var top_left := map.to_global(
map.map_to_local(used.position) - cell * 0.5)
var bottom_right := map.to_global(
map.map_to_local(used.end) - cell * 0.5)
cam.limit_left = int(top_left.x)
cam.limit_top = int(top_left.y)
cam.limit_right = int(bottom_right.x)
cam.limit_bottom = int(bottom_right.y)- 터레인을 설정하고 벽을 다시 그려보세요. 모서리가 자동으로 맞습니까?
Y Sort를 켜고 나무 타일 앞뒤로 걸어보세요 (6강).- 커스텀 데이터로 "물" 타일을 만들어 이동 속도를 절반으로 만들어보세요.
Foreground레이어에 지붕을 그리고 그 아래로 들어가 보세요.
- 개발자 — 맵 데이터를 코드로 생성해야 한다면(랜덤 던전)
set_cell()을 반복문으로 씁니다. 대량 수정 시에는TileMapLayer를 여러 번 갱신하지 말고 한 번에 처리하세요. - 기획자 — 레벨 디자인은 직접 그리는 게 가장 빠릅니다. 타일 팔레트만 준비되면 개발자 없이도 스테이지를 만들 수 있습니다. "이 방은 어렵게" 같은 요청보다 직접 그린 맵 하나가 소통 비용이 훨씬 적습니다.
- 디자이너 — 타일셋 제작 규칙을 초기에 정하세요. 타일 크기 / 팔레트 / 이음새 규칙 / 터레인 대응 여부. 특히 타일 사이에 1px 여백(padding) 을 두면 확대 시 인접 타일 색이 새어 나오는 현상(bleeding)을 막을 수 있습니다.
"타일을 칠했는데 충돌이 없다"
→ ① 물리 레이어를 추가 안 함, ② 개별 타일에 폴리곤을 안 그림,
③ Collision Layer 번호가 플레이어 마스크와 안 맞음(11강).
"타일 사이에 얇은 선이 보인다"
→ 텍스처 블리딩입니다.
프로젝트 설정 → Rendering → Textures → Canvas Textures → Default Texture Filter 를 Nearest 로,
그리고 타일셋 이미지에 여백을 두거나 TileSet의 Separation 값을 설정하세요.
"map_to_local 결과가 반 칸 어긋난다"
→ map_to_local()은 타일 중심을 줍니다. 좌상단이 필요하면 타일 크기의 절반을 빼세요.
"터레인으로 그렸는데 이상한 타일이 나온다" → 터레인 비트 칠하기가 빠진 타일이 있습니다. 각 타일의 모든 모서리/변을 확인하세요.
- 타일셋을 만들고 타일을 칠했다
- 타일에 충돌이 붙어 캐릭터가 막힌다
- 레이어를 나눠 배경/지형/장식을 분리했다
- 타일 좌표와 월드 좌표를 변환할 수 있다
- 카메라 리미트를 맵에 맞췄다
다음 강의 — 스테이지가 생겼습니다. 이제 타이틀 → 게임 → 결과 로 이어지는 게임 전체 흐름과 저장을 만듭니다. P5의 마지막입니다.