끝없이 이어지는 세계는
어떻게 만들어지는가
· 월드 생성 · 기술 노트

이번 글은 RogueForge의 세계가 어떻게 만들어지는지, 그리고 지난주에 그 세계를 끝없이 이어지는 둥근 세계로 바꾸면서 무엇을 배웠는지 정리한 것입니다. 지형, 기후, 강, 동굴은 전부 시드 하나에서 계산되고 저장하지 않습니다. 같은 시드면 어느 컴퓨터에서든 같은 땅이 나옵니다.
끝없는 탐험을 위해 세계를 둥글게 말았습니다
원래 세계는 유한한 평면이었고, 원점에서 멀어질수록 어려워지는 구조였습니다. 지구처럼 어느 방향으로 가도 반대편으로 이어지는 세계를 원했고, 그래서 세계를 토러스로 바꿨습니다. 가로 둘레는 41,600타일로 뛰어서 약 4시간 거리이고, 세로는 그 절반인 20,800타일로 지구 비율을 따랐습니다. 극은 하나, 적도도 하나입니다.
둥근 세계에서 가장 까다로운 것은 이음매입니다. 두 점의 거리를 그냥 빼면 이음매 건너편의 상대가 “반 바퀴 떨어진” 것으로 계산되어 몬스터가 바로 옆의 플레이어를 보지 못합니다. 그래서 좌표 차이는 항상 감아서 잽니다.
DX(x1, x0) = d − W · round(d / W), d = x1 − x0
시뮬레이션에서 좌표를 직접 빼던 990여 곳을 이 함수로 바꿨습니다. 그리고 이 버그는 이음매에서만 납니다. 시작 지점 근처의 검사는 전부 통과하기 때문에, 검사용으로는 둘레를 4,096타일로 줄인 작은 세계를 따로 만들어 이음매 양쪽을 직접 비교합니다.
노이즈도 감아야 땅이 이어집니다
지형은 노이즈로 만듭니다. 그런데 평범한 2D 노이즈는 x = 0과 x = 41,600에서 다른 값을 내므로 이음매에 절벽이 생깁니다. 해법은 2D 좌표를 4차원 공간의 두 원 위에 올려 4D 노이즈를 읽는 것입니다. 원을 한 바퀴 돌면 정확히 같은 점으로 돌아오므로 이음매가 원리적으로 사라집니다.
Torus(u, v) = N4( R·cos(2πu/W), R·sin(2πu/W), R′·cos(2πv/H), R′·sin(2πv/H) ), R = 둘레 / 2π
한 가지 함정이 있었습니다. 4D 노이즈는 2D보다 진폭이 작습니다. 표본 2만 개를 재 보니 2D는 0.444, 4D는 0.293이었습니다. 그대로 쓰면 지형이 66%로 납작해져서 층 분포가 무너졌습니다. 그 비율의 역수인 1.515를 곱해 옛 진폭을 되찾았습니다. 눈으로 보면 “조금 밋밋한가” 정도라, 숫자로 재지 않았다면 놓쳤을 것입니다.
바다 40%는 스윕으로 찾았습니다
높이는 한 함수가 정합니다. 파장 1,111타일의 큰 노이즈가 대륙과 바다를 가르고, 그 위에 4옥타브 기복이 얹힙니다. 육지는 해수면 위로 부드럽게 바닥을 걸어 두어 육지 한복판에 웅덩이가 생기지 않게 했고, 높이가 올라갈수록 포화시켜 걸어 다닐 수 있는 단차만 남겼습니다. 화면의 블록 한 층은 시뮬레이션 높이 14층입니다.
level = floor( (h − 3) / 14 )

바다 비율은 육지 바이어스 상수 하나가 정하는데, 이 값은 선형이 아닙니다. 바이어스 34에서 바다 2%, 10에서 33%, 0에서 52%였습니다. 그래서 눈대중 대신 이분 탐색 검사로 40%가 되는 값을 찾았고, 노이즈를 4D로 바꿀 때 다시 찾아 3.9가 됐습니다. 이 스윕은 한 시간이 걸려서 평소 회귀 검사에서는 빼 두고, 찾은 값이 유지되는지만 매번 확인합니다.
비율만 재면 놓치는 것이 있었습니다. 바다 40%인데 물이 553개 조각으로 흩어진 세계도 40%입니다. 덩어리 크기는 진폭이 아니라 주파수가 정한다는 것을 스윕에서 배웠고, 대륙 파장을 278에서 1,111타일로 늘려 가장 큰 바다가 전체 물의 32%를 차지하게 했습니다.
기후는 위도가 정합니다
둥근 세계에는 “원점에서 멀리”라는 개념이 없어서, 거리로 정하던 기후와 난이도 링을 버렸습니다. 대신 위도가 온도의 72%를 정하고 나머지는 지역 노이즈입니다. 적도에서 극으로 갈수록 사막, 초원과 숲, 툰드라로 바뀌고, 극 둘레 12%는 바다라 배로 건너야 합니다. 시작 지점은 적도와 극의 한가운데 온대에 있습니다.

| 온도 | 바이옴 |
|---|---|
| 0.27 미만 | 툰드라 |
| 0.27~0.64 | 습하면 숲·늪, 아니면 초원 |
| 0.64~0.83 | 습하면 숲, 아니면 사막 |
| 0.83 이상 | 사막, 지역 노이즈가 높으면 화산 |
바이옴 패치, 화산, 동굴처럼 좌표를 격자로 나누는 시스템은 전부 격자 수를 둘레에 정수 개로 맞췄습니다. 강의 발원지 격자가 112타일이었는데 둘레를 나누지 못해, 같은 자리의 강이 이음매 양쪽에서 다르게 나오는 것을 검사가 잡았습니다.
강은 내리막을 따라 바다까지 흐릅니다
내륙 물의 정본은 강입니다. 격자 칸마다 82% 확률로 발원지가 생기고, 가장 높은 후보에서 출발해 3타일씩 내리막을 따라 최대 600타일을 흐릅니다. 경사가 약한 평지에서는 방향이 잡음이 되기 쉬워, 그때는 바깥쪽으로 흐르려는 힘을 키우고 사행을 섞습니다. 바다에 닿지 못한 물줄기는 통째로 버립니다.
강바닥은 흐름이 굵어질수록 넓고 깊어지며, 가파른 둑과 완만한 계곡이 이어집니다. 8타일이 안 되는 작은 물웅덩이는 메워서 지도가 점박이가 되지 않게 했습니다. 물인지 아닌지는 함수 하나가 정하고, 계단 구덩이 칸은 해수면 아래여도 물이 아닙니다.
지하동굴은 계단 구멍으로 내려갑니다
동굴은 지표와 같은 좌표 위의 다른 평면입니다. 440타일 격자마다 34% 확률로 개미굴 모양의 동굴이 생기고, 중심에서 네 갈래가 뻗어 갈래마다 홀 두 개가 달립니다. 지표에는 ㄱ자 계단 세 칸이 나 있어 한 칸에 블록 한 층씩 내려갑니다. 입구는 3층 깊이에서 시작해 멀어질수록 깊어지며 최대 5층까지 내려갑니다.

검증과 남은 일
이음매·기후·강 반복 검사 7건, 지형 연속성 3건, 바다 비율 회귀 3건이 매번 돕니다. 토러스 전환 후속까지 고유 검사 61건을 통과했습니다. 시드 1의 시작 지점이 바다였던 문제는 반경 300타일 안을 대륙으로 끌어올려 고쳤고, 5개 시드에서 시작 지점 주변 물 0%를 확인했습니다.
지형이 전면적으로 바뀌어 기존 세이브의 땅은 어긋납니다. 이 변경은 아직 게임 배포 전이며, 남은 일은 타일 사전의 이음매 처리, 던전을 별도 평면으로 옮기는 것, 화면 분할에서 두 사람이 이음매 반대편에 선 경우의 실기 확인입니다.