TL;DR — Godot 4의 Terrain TileSet은 단순히 정확한 8-bit mask 하나를 찾아 끼우는 방식이 아닙니다.
connect와path가 만든 constraint를 기준으로 TileSet 후보 pattern에 penalty를 매기고, 가장 낮은 penalty의 pattern을 선택합니다. 이 관점은Match Sides,Match Corners,Match Corners and Sides의 차이와 예상과 다른 fallback 결과를 설명하는 데 도움이 됩니다.
Table of contents
Open Table of contents
- 들어가며
- 1. Terrain TileSet은 tile 자체가 아니라 terrain pattern을 고릅니다
- 2. Center terrain과 peering bit
- 3. Match mode는 어떤 peering bit를 볼지 정합니다
- 4. 3x3 case study로 보는 bit 변화
- 5.
connect는 같은 terrain 영역을 만들고,path는 입력 순서를 연결합니다 - 6. Constraint는 shared edge/corner에 걸리는 요구사항입니다
- 7. 기존 peering bit는 약한 constraint가 됩니다
- 8. Constraint가 없으면 기존 pattern 보존이 강하게 작동합니다
- 9. TileSet을 만들 때 가져갈 기준
- 정리하며
- 참고 자료
들어가며
Godot 4의 Terrain TileSet은 2D 타일맵에서 지형 경계를 자동으로 맞춰 주는 기능입니다. 에디터에서 terrain을 칠하면 주변 타일을 보고 적절한 모양의 tile이 선택됩니다.
처음에는 이 기능을 “주변 8칸을 보고 정확한 bitmask에 맞는 tile을 선택하는 기능”으로 이해했습니다. 하지만 Match Corners and Sides에서 corner가 기대처럼 붙지 않거나, set_cells_terrain_connect()와 set_cells_terrain_path()의 결과가 다르게 나오는 경우를 보면서 이 설명만으로는 부족하다는 것을 알게 되었습니다.
이 글은 Godot 공식 문서, Godot 엔진 소스 코드, 그리고 Terrain Set 설명 자료를 함께 보며 정리한 학습 기록입니다. 목표는 API 사용법을 나열하는 것이 아니라, 실제 TileSet을 만들고 디버깅할 때 사용할 수 있는 판단 기준을 세우는 것입니다.
이 글에서 다루는 내용:
center terrain과peering bit의 역할Match Sides,Match Corners,Match Corners and Sides의 차이connect와path가 constraint를 만드는 방식- 정확히 맞는 terrain pattern이 없을 때 fallback이 일어나는 방식
- TileSet 제작과 디버깅에서 사용할 수 있는 실전 기준
사전 지식: Godot 4의
TileMapLayer,TileSet, atlas tile, terrain set을 한 번 이상 사용해 본 경험을 전제로 합니다. 또한 square tile을 기준으로 설명을 진행합니다.
1. Terrain TileSet은 tile 자체가 아니라 terrain pattern을 고릅니다
Godot 공식 문서는 terrain을 Godot 3.x의 autotile을 대체하는 더 강력한 기능으로 설명합니다. 중요한 차이는 terrain이 별도의 tile 종류가 아니라, atlas tile에 부여되는 속성이라는 점입니다.
즉 Terrain TileSet을 사용할 때, 엔진이 선택하는 tile은 다음 정보를 기반으로 선택된 atlas tile입니다.
center terrain + terrain peering bits
= terrain pattern
그리고 같은 terrain pattern을 가진 tile이 여러 개 있으면, 마지막에는 해당 pattern을 가진 실제 tile 중 하나를 선택합니다. 이때 TileData.probability가 있으면 그 값이 tile 선택에 영향을 줍니다.
이 흐름을 구분하는 것이 중요합니다.
terrain pattern 선택
-> pattern을 가진 실제 atlas tile 선택
-> TileMapLayer에 set_cell
따라서 예상과 다른 tile이 배치될 때는 먼저 “이미지가 왜 선택됐지?”가 아니라 “어떤 terrain pattern이 선택됐지?”를 봐야 합니다.
2. Center terrain과 peering bit
이제부터 본격적으로 terrain pattern에 대해 알아볼 것입니다. 먼저 알아야 할 개념은 center terrain(= center bit)과 peering bit입니다.
하나의 square terrain cell은 개념적으로 다음과 같은 3x3 bit grid로 표현합니다.
top_left_corner top_side top_right_corner
left_side center right_side
bottom_left_corner bottom_side bottom_right_corner
center는 해당 cell 자체가 어떤 terrain에 속하는지를 나타냅니다. Godot 코드에서는 후보 pattern의 get_terrain() 값으로 비교됩니다.
peering bit는 주변 cell과 맞닿는 edge 또는 corner가 어떤 terrain이어야 하는지를 나타냅니다. Square TileSet에서 Match Corners and Sides를 사용하면 side 4개와 corner 4개, 총 8개의 peering bit가 비교 대상이 됩니다.
표기로 바꾸면 다음과 같습니다.
■ = on bit
□ = off bit
단일 cell:
□□□
□■□
□□□
가운데 ■는 center terrain입니다. 주변 8칸은 match mode에 따라 사용 여부가 달라지는 peering bit입니다.
3. Match mode는 어떤 peering bit를 볼지 정합니다
Terrain set의 match mode는 “어떤 bit를 비교에 사용할 것인가”를 정합니다. Godot 엔진의 TileSet::is_valid_terrain_peering_bit_for_mode()는 CellNeighbor 하나를 받아 현재 mode에서 그 bit를 사용할 수 있는지 검사합니다.
Square TileSet 기준으로 정리하면 다음과 같습니다.
| Match mode | 사용하는 bit | 해석 |
|---|---|---|
Match Sides | 상하좌우 side | edge로 맞닿은 이웃만 봅니다. |
Match Corners | 네 corner | 하나의 꼭짓점을 공유하는 cell 묶음을 봅니다. |
Match Corners and Sides | side 4개 + corner 4개 | side와 corner를 모두 보지만, corner 조건이 느슨해지는 것은 아닙니다. |
개념적인 비교 mask는 다음과 같습니다.
Match Sides:
□■□
■C■
□■□
Match Corners:
■□■
□C□
■□■
Match Corners and Sides:
■■■
■C■
■■■
여기서 C는 center terrain입니다. Center는 peering bit가 아니므로 is_valid_terrain_peering_bit_for_mode()로 필터링되지 않고, 후보 pattern의 center terrain과 별도로 비교됩니다.
이 지점에서 중요한 오해가 하나 생깁니다. Match Corners and Sides라는 이름 때문에 corner 연결 조건도 쉽게 켜질 것처럼 보이지만, 실제로는 side와 corner가 모두 유효 bit가 될 뿐입니다. Corner는 여전히 해당 꼭짓점을 공유하는 cell들이 모두 같은 terrain center를 가질 때 constraint가 만들어집니다.
4. 3x3 case study로 보는 bit 변화
아래 예시는 하나의 큰 칸을 terrain cell로 보고, 그 내부를 다시 3x3 bit grid로 표현한 것입니다.
□□□
□■□
□□□
4.1 Single Cell
같은 terrain 이웃이 없으면 모든 mode에서 center만 켜집니다.
□□□│□□□│□□□
□□□│□□□│□□□
□□□│□□□│□□□
───┼───┼───
□□□│□□□│□□□
□□□│□■□│□□□
□□□│□□□│□□□
───┼───┼───
□□□│□□□│□□□
□□□│□□□│□□□
□□□│□□□│□□□
4.2 Horizontal Pair
가로로 붙은 두 cell은 Match Sides와 Match Corners and Sides에서 서로 바라보는 side bit가 켜집니다.
□□□│□□□│□□□
□□□│□□□│□□□
□□□│□□□│□□□
───┼───┼───
□□□│□□□│□□□
□□□│□■■│■■□
□□□│□□□│□□□
───┼───┼───
□□□│□□□│□□□
□□□│□□□│□□□
□□□│□□□│□□□
Match Corners에서는 side를 사용하지 않으므로 두 cell 모두 center만 켜집니다.
4.3 Diagonal Pair
대각선으로만 닿은 두 cell은 side를 공유하지 않습니다. 또한 하나의 corner를 완성하는 4개 cell 조건도 만족하지 않습니다.
□□□│□□□│□□□
□□□│□□□│□□□
□□□│□□□│□□□
───┼───┼───
□□□│□□□│□□□
□□□│□■□│□□□
□□□│□□□│□□□
───┼───┼───
□□□│□□□│□□□
□□□│□□□│□■□
□□□│□□□│□□□
따라서 Match Corners and Sides에서도 대각선 pair만으로 corner bit가 켜지지 않습니다.
4.4 2x2 Block
2x2 block은 side와 corner 조건을 모두 만족합니다. 특히 가운데 공유 corner는 네 cell이 모두 같은 terrain center를 가지므로 corner bit가 켜집니다.
□□□│□□□│□□□
□□□│□□□│□□□
□□□│□□□│□□□
───┼───┼───
□□□│□□□│□□□
□□□│□■■│■■□
□□□│□■■│■■□
───┼───┼───
□□□│□■■│■■□
□□□│□■■│■■□
□□□│□□□│□□□
이 차이 때문에 Match Corners 계열은 “대각선으로 닿았다”보다 “공유 vertex를 이루는 cell 묶음이 완성되었는가”가 중요합니다.
5. connect는 같은 terrain 영역을 만들고, path는 입력 순서를 연결합니다
TileMapLayer에는 terrain을 배치하는 대표 함수가 두 개 있습니다. Godot 에디터의 TileMap에서 terrain을 배치하는 아이콘과 동일한 기능을 합니다.
set_cells_terrain_connect(cells, terrain_set, terrain, ignore_empty_terrains)
set_cells_terrain_path(path, terrain_set, terrain, ignore_empty_terrains)
공식 문서에서 connect는 입력 cell이 같은 terrain을 가진 이웃과 닿으면 둘을 연결하려고 하며, 필요한 경우 주변 tile도 업데이트할 수 있다고 설명합니다. 반면 path는 path 안의 연속된 두 cell을 같은 terrain으로 연결합니다.
공식 문서의 설명만으로는 이 두 방식의 차이를 직관적으로 이해하기가 어렵습니다. 엔진 코드 기준으로 보면 둘의 차이는 constraint를 만드는 방식에서 더 명확하게 드러납니다.
5.1 connect
connect는 입력 cell을 칠할 대상인 동시에, 주변의 기존 cell 중 center terrain이 같은 cell도 같은 영역으로 봅니다.
개념적으로는 다음 집합을 만듭니다.
painted_set:
이번 호출에 직접 입력된 cells
can_modify_list:
painted_set + 주변 neighbor cells
cells_with_terrain_center_bit:
painted_set + 기존 center terrain이 같은 주변 cells
그 다음 입력 cell을 순회하며 constraint를 만듭니다.
입력 cell center = 요청한 terrain, priority 10
같은 terrain center 이웃과 공유하는 side = 요청한 terrain, priority 10
같은 terrain center cell들이 공유하는 corner = 요청한 terrain, priority 10
여기서 priority는 우선 선택 보너스가 아니라, constraint를 어겼을 때 더해지는 penalty입니다.
candidate value != constraint terrain
=> score += priority
따라서 priority 10은 “이번 호출의 의도”를 강하게 지키라는 뜻입니다.
5.2 path
path는 같은 center terrain을 가진 주변 cell을 자동으로 영역에 포함하지 않습니다. 입력 path의 연속 pair만 강한 peering constraint를 만듭니다.
path = [A, B, C]
A.center = terrain, priority 10
B.center = terrain, priority 10
C.center = terrain, priority 10
A-B 방향 peering bit = terrain, priority 10
B-C 방향 peering bit = terrain, priority 10
반대로 path 길이가 1이면 center constraint만 생기고, peering constraint는 생기지 않습니다.
이 차이 때문에 path([X])와 connect([X])는 같은 좌표 하나를 칠하더라도 주변 같은 terrain과 연결되는 강도가 다릅니다.
6. Constraint는 shared edge/corner에 걸리는 요구사항입니다
Godot 내부의 TerrainConstraint는 다음과 같은 의미로 이해합니다.
- 어느 center, shared edge, shared corner가 어떤 terrain이어야 하는가
- 그 값을 어기면 penalty를 몇 점 줄 것인가
개념적으로 표현하면 다음과 같습니다.
Constraint {
position,
bit_or_center,
terrain,
priority
}
여기서 주의할 점은 TerrainConstraint가 단순히 “특정 cell의 로컬 bit 하나”에만 걸리는 규칙이 아니라는 점입니다. Side와 corner는 여러 cell에서 같은 물리적 경계를 가리킵니다.
예를 들어 가로로 붙은 두 cell A, B가 있을 때:
A.right_side
B.left_side
두 bit는 서로 다른 tile 안에 있지만 같은 shared side를 표현합니다.
A | B
^
shared side
Corner도 마찬가지입니다.
A B
C D
가운데 vertex는 다음 네 bit가 공유합니다.
A.bottom_right_corner
B.bottom_left_corner
C.top_right_corner
D.top_left_corner
Godot은 TerrainConstraint를 만들 때 이 shared side/corner를 canonical 위치로 정규화합니다. 그래서 어느 cell에서 시작했는지와 상관없이 같은 physical edge 또는 vertex는 같은 constraint key로 비교됩니다.
6.1 X-R shared side 예시
기존에 X가 있고, 오른쪽에 R을 새로 칠한다고 가정합니다.
X R
Match Sides 또는 Match Corners and Sides에서 connect([R])를 호출했고, X의 center terrain도 R과 같은 terrain 1이라면 X-R 사이 shared side에 강한 constraint가 만들어집니다.
X-R shared side = terrain 1, priority 10
이 constraint는 로컬 bit로 보면 다음 두 표현에 동시에 해당합니다.
X.right_side = terrain 1
R.left_side = terrain 1
후보 평가 때는 각 cell이 자기 로컬 bit로 같은 shared side constraint를 확인합니다.
X 후보가 다음과 같으면:
□■□
□■■
□□□
X.right_side가 terrain 1이므로 constraint와 일치합니다.
penalty += 0
반대로 X 후보가 다음과 같으면:
□■□
□■□
□□□
X.right_side가 비어 있으므로 X-R shared side = terrain 1 constraint를 어깁니다.
penalty += 10
같은 constraint는 R 후보를 평가할 때도 R.left_side 기준으로 비교됩니다. 즉 constraint는 grid 위의 shared edge/corner에 걸리고, 그 constraint를 공유하는 cell들은 각자의 로컬 bit로 같은 규칙을 검사합니다.
7. 기존 peering bit는 약한 constraint가 됩니다
connect와 path는 입력 cell뿐 아니라 주변 cell도 can_modify_list에 넣습니다. 주변 tile도 바뀔 수 있어야 경계가 자연스럽게 이어지기 때문입니다.
하지만 주변 tile을 아무렇게나 바꾸면 기존 맵의 경계가 망가집니다. 이때 _get_terrain_constraints_from_painted_cells_list()가 기존 주변 상태를 읽고 약한 constraint를 만듭니다.
흐름은 다음과 같습니다.
painted cell의 유효 peering bit를 순회
-> 같은 shared side/corner를 표현하는 주변 cell/bit를 수집
-> 기존 TileData의 peering bit terrain을 카운트
-> 가장 많이 나온 terrain을 대표 terrain으로 선택
-> priority 1 constraint로 추가
즉 shared side/corner에는 “기존 타일들이 이 경계를 어떤 terrain으로 보고 있었는가”라는 다수결 대표값이 생깁니다.
priority 1은 새로 칠하는 의도보다 약합니다. 새 center terrain이나 새 연결은 보통 priority 10으로 들어가기 때문입니다. 그래도 정확한 후보 pattern이 없을 때는 이 약한 constraint가 fallback 결과에 영향을 줍니다.
8. Constraint가 없으면 기존 pattern 보존이 강하게 작동합니다
가장 중요한 부분은 fallback입니다.
처음에는 정확히 일치하는 bitmask가 없으면 CellNeighbor enum 순서대로 다음 후보를 찾는다고 생각하기 쉽습니다. 실제 흐름은 그렇지 않습니다.
_get_best_terrain_pattern_for_constraints()는 TileSet에 등록된 terrain pattern 후보를 모두 평가합니다.
평가 흐름은 다음과 같습니다.
1. 후보 pattern의 center terrain을 constraint와 비교
2. match mode에서 유효한 peering bit만 순회
3. constraint가 있는 bit는 terrain 값이 다르면 score += priority
4. constraint가 없는 bit는 기존 current pattern과 달라지면 후보에서 제외
5. score가 가장 낮은 pattern을 선택
즉 후보 평가에는 두 종류의 규칙이 같이 작동합니다.
| 구분 | 코드상 형태 | 후보가 다를 때 |
|---|---|---|
| 명시 constraint | TerrainConstraint 객체가 있음 | score += priority |
| 보존 규칙 | TerrainConstraint 객체가 없음 | current_pattern과 다르면 후보 제외 |
여기서 “constraint가 없다”는 말은 match mode에서 해당 bit를 보지 않는다는 뜻이 아닙니다. Match mode 안에 있는 bit인데, 이번 connect/path/기존 상태 보존 계산에서 그 shared edge/corner에 대한 명시 요구사항이 만들어지지 않았다는 뜻입니다.
정리하면 다음과 같습니다.
match mode 밖의 bit:
평가하지 않음
match mode 안에 있고 명시 constraint가 있는 bit:
constraint terrain과 비교하고, 다르면 penalty 누적
match mode 안에 있지만 명시 constraint가 없는 bit:
기존 current_pattern과 비교하고, 다르면 후보 제외
이 구조 때문에 constraint가 없는 bit는 “자유롭게 바꿔도 되는 bit”가 아닙니다. 오히려 기존 pattern을 유지해야 하는 영역이 됩니다.
8.1 명시 constraint가 있는 경우
기존 X가 다음 pattern을 가지고 있다고 가정합니다.
□■□
□■□
□□□
의미는 다음과 같습니다.
center = terrain 1
top_side = terrain 1
right_side = empty
bottom_side = empty
left_side = empty
이제 오른쪽에 R을 새로 칠했고, connect 규칙에 의해 X-R 사이 shared side constraint가 생겼습니다.
X-R shared side = terrain 1, priority 10
후보 A:
□■□
□■■
□□□
후보 A는 X.right_side = terrain 1입니다.
constraint와 일치
=> penalty 0
=> 후보 유지
후보 B:
□■□
□■□
□□□
후보 B는 X.right_side = empty입니다.
constraint와 불일치
=> penalty +10
=> 후보 유지
명시 constraint가 있는 경우에는 값이 달라도 바로 탈락하지 않습니다. 대신 priority만큼 점수가 나빠집니다. 정확한 pattern이 없을 때는 이런 후보도 fallback 선택 대상에 남습니다.
8.2 명시 constraint가 없는 경우
이번에는 X.bottom_side에 대해 어떤 명시 constraint도 없다고 가정합니다.
기존 값은 다음과 같습니다.
current_pattern.bottom_side = empty
후보 C:
□■□
□■■
□□□
후보 C도 bottom_side = empty입니다.
명시 constraint 없음
current_pattern과 같음
=> 후보 유지
후보 D:
□■□
□■■
□■□
후보 D는 bottom_side = terrain 1입니다.
명시 constraint 없음
current_pattern과 다름
=> 후보 제외
이 경우에는 penalty를 더하지 않고 후보에서 제외합니다. 즉 명시 constraint가 없는 bit는 사실상 기존 상태 보존이 강하게 적용됩니다.
8.3 path([R])에서 constraint가 없는 경우
다음처럼 기존 X 오른쪽에 R을 칠한다고 가정합니다.
X R
connect([R])라면 X가 같은 center terrain일 때 X-R shared side = terrain 1 constraint가 만들어집니다.
하지만 path([R])는 path 길이가 1이므로 연속 pair가 없습니다. 이 경우 강한 constraint는 R.center = terrain 1뿐입니다.
R.center = terrain 1, priority 10
X-R shared side constraint 없음
따라서 X가 can_modify_list에 들어와 후보 재평가 대상이 되더라도, X.right_side를 terrain 1로 켜라는 명시 constraint는 없습니다.
기존 X:
□■□
□■□
□□□
후보 X:
□■□
□■■
□□□
이 후보는 X.right_side를 empty에서 terrain 1로 바꿉니다.
X-R shared side constraint 없음
current_pattern.right_side와 다름
=> 후보 제외
이 예시가 connect와 path의 차이를 잘 보여줍니다. path에서는 주변에 같은 terrain center가 있다는 사실만으로 shared edge constraint가 생기지 않습니다. path 배열 안에서 연속된 pair로 입력되어야 강한 peering constraint가 만들어집니다.
8.4 Corner constraint가 없는 경우
Match Corners and Sides에서도 corner constraint가 항상 생기지는 않습니다.
다음 배치를 봅니다.
A B
R .
R을 새로 칠하고 A, B, R이 모두 terrain 1이라고 해도, 오른쪽 아래 cell이 비어 있으면 네 cell이 하나의 corner를 완성하지 못합니다.
이 경우 해당 shared corner에 대해 다음 조건을 만족하지 못합니다.
corner를 공유하는 모든 cell의 center terrain이 terrain 1인가?
=> 아니오
따라서 corner constraint가 만들어지지 않습니다.
후보가 이 corner bit를 새로 켜려고 하면, 명시 constraint가 없으므로 기존 current_pattern과 비교됩니다. 기존 pattern에서 해당 corner가 비어 있었다면, corner bit가 켜진 후보는 제외됩니다.
이 때문에 Match Corners and Sides에서 대각선 또는 L자 모양이 기대보다 덜 연결되어 보이는 경우가 생깁니다. Side constraint는 만들어질 수 있지만, corner constraint는 공유 corner를 이루는 cell 조건이 충족되어야 만들어집니다.
즉 정확히 일치하는 pattern이 있으면 score 0으로 선택됩니다. 정확히 일치하는 pattern이 없으면, 명시 constraint가 있는 범위 안에서 더 중요한 constraint를 덜 깨는 pattern이 선택됩니다. 명시 constraint가 없는 범위는 fallback의 자유도가 아니라 기존 pattern 보존 조건으로 작동합니다.
이때 priority의 의미는 다음처럼 정리합니다.
| Priority | 출처 | 의미 |
|---|---|---|
10 | 이번 입력 cell의 center, connect 연결, path 연속 pair | 이번 호출의 직접 의도 |
5 | 앞에서 이미 선택된 pattern의 후속 전파 | 같은 호출 안에서 앞 cell의 선택 결과 |
1 | 기존 주변 bit 보존 | 기존 맵 상태를 가능한 한 유지 |
terrain_fill_constraints()는 can_modify_list를 순회하면서 cell 하나의 pattern을 고른 뒤, 그 결과를 priority 5 constraint로 다시 추가합니다.
cell A pattern 선택
-> A의 center/peering bit를 priority 5 constraint로 추가
-> 다음 cell B 평가에 A의 결과가 영향을 줌
이 과정은 반복 수렴 solver가 아니라 한 번 훑는 greedy 흐름입니다. 앞에서 고른 pattern은 뒤 cell에 영향을 주지만, 뒤 cell 때문에 앞 cell을 다시 계산하지 않습니다.
9. TileSet을 만들 때 가져갈 기준
이 내용을 실전 기준으로 바꾸면 다음과 같습니다.
첫째, Match Corners and Sides는 “side와 corner를 모두 쉽게 연결하는 mode”가 아닙니다. Side와 corner를 모두 비교 대상으로 삼는 mode입니다. Corner는 여전히 공유 vertex를 이루는 cell 조건을 만족해야 합니다.
둘째, side 기반 지형 연결이 목적이면 Match Sides가 더 직관적입니다. 특히 2D 탑다운 맵이나 절차적 맵 생성에서 “상하좌우로 붙으면 연결된다”는 모델이 필요하다면 Match Sides가 디버깅하기 쉽습니다.
셋째, path는 선형 경로나 브러시 stroke처럼 입력 순서가 중요한 배치에 적합합니다. 주변에 같은 terrain center가 있더라도 path에 포함되지 않았으면 강한 연결 constraint가 만들어지지 않습니다.
넷째, procedural generation에서 대량으로 terrain을 칠할 때는 set_cell()로 직접 atlas tile을 고르는 방식과 set_cells_terrain_connect()로 terrain pattern을 고르는 방식을 구분해야 합니다. Terrain system은 주변 tile 정보를 바탕으로 후보 pattern을 계산하는 기능입니다. 이 계산이 없으면 TileSet에 terrain metadata를 설정해도 자동 연결 결과는 나오지 않습니다.
다섯째, 정확한 pattern tile을 충분히 준비해야 합니다. Godot 공식 문서도 terrain connection method가 잘 작동하려면 TileSet에 필요한 terrain 조합이 준비되어 있어야 한다고 설명합니다. 필요한 조합이 없으면 Godot은 실패하는 것이 아니라 penalty가 가장 낮은 후보를 고릅니다. 이 결과가 사용자 입장에서는 “이상한 fallback”처럼 보입니다.
정리하며
Godot Terrain TileSet을 이해할 때 가장 도움이 된 관점은 다음 문장입니다.
TileSet은 자동으로 정답을 만들어 주는 시스템이 아니라,
constraint 평가에 들어갈 terrain pattern 후보군입니다.
핵심 요약:
center terrain은 cell 자체의 terrain이고,peering bit는 주변 side/corner와 맞물리는 terrain 값입니다.Match Sides,Match Corners,Match Corners and Sides는 사용할 peering bit 집합을 정합니다.connect는 같은 center terrain 주변 cell까지 영역처럼 보고 강한 연결 constraint를 만듭니다.path는 입력 path의 연속 pair만 강한 peering constraint로 연결합니다.- 정확히 맞는 terrain pattern이 없으면 enum 순서가 아니라 constraint penalty가 가장 낮은 후보가 선택됩니다.
- 실전 TileSet 제작에서는 필요한 terrain pattern을 충분히 준비하고,
Match Sides와Corners and Sides의 디버깅 난이도를 구분해야 합니다.
이 기준을 가지고 TileSet을 설계하면, “왜 이 타일이 나왔지?”라는 질문을 “어떤 constraint 때문에 이 pattern이 선택됐지?”라는 질문으로 바꾸게 됩니다.
참고 자료
- Godot Docs: Using TileSets - Creating terrain sets (autotiling) — terrain set, terrain mode, peering bit의 공식 문서 설명입니다.
- Godot Docs: TileMapLayer —
set_cells_terrain_connect()와set_cells_terrain_path()API 설명입니다. - Godot Engine Source:
tile_map_layer.cpp— terrain constraint 생성, 후보 pattern 평가,connect/path구현을 확인한 소스입니다. - Godot Engine Source:
tile_set.cpp—is_valid_terrain_peering_bit_for_mode()구현을 확인한 소스입니다. - Godot Engine Source:
tile_set.h—CellNeighbor와TerrainModeenum 정의를 확인한 소스입니다. - dandeliondino/godot-4-tileset-terrains-docs — Godot 4 TileSet terrain sets를 시각 자료와 예제 프로젝트로 자세히 설명한 참고 repository입니다.
- Godot Forum: TileSet Terrain Sets — 위 terrain sets 문서 repository를 소개한 Godot 포럼 글입니다.
이 게시물은 학습한 내용을 바탕으로 초안을 작성한 뒤, LLM의 도움을 받아 내용을 검수하고 다듬어 완성되었습니다.