← 모든 글

픽셀 아트의 길: iPhone에서 만드는 맵 연결과 구역

포켓몬의 첫 세 세대는 모두 16픽셀 셀 하나를 16프레임에 걷습니다. 초당 약 3.73셀입니다. Kiradex의 수집가는 초당 4타일을 걷기 때문에, 옛 게임에서 측정한 길은 타일당 0.25초라는 일정한 비율로 우리 마을에 환산됩니다.1234 각 게임의 첫 도로는 게임기 화면 2~6장 길이이고 트레이너가 없습니다. 첫 구간, 즉 플레이어의 현관에서 다음 마을의 포켓몬센터까지는 Emerald에서 58셀, 걸어서 15.5초이고 FireRed에서 94셀, 25.2초입니다. 돌아오는 길은 두 게임 모두 더 짧아 각각 42셀과 76셀인데, 그 도로의 턱이 모두 집 쪽을 향하기 때문입니다.567 그림이 바뀌는 곳에서 관동은 길 위에 건물을 세웁니다. Red의 맵 연결 78개 가운데 76개는 같은 타일셋끼리 이어지고, 서로 다른 두 장소를 잇는 Red의 게이트는 하나같이 두 타일셋을 잇습니다.8 호연의 엔진은 이웃 맵의 7셀을 현재 맵 둘레의 여백에 세 변으로 복사하고 동쪽에만 8셀을 복사해 현재 맵의 타일로 그리며, 경계를 넘는 순간 이웃 맵 고유의 보조 타일과 팔레트를 페이드 없이 불러옵니다.910 Emerald의 지도 화면은 28×15칸의 격자입니다. Littleroot에 있는 플레이어 집 2층의 벽 지도로 열 수 있고, Rustboro부터는 포켓내비로 들고 다닙니다. 방문 여부와 관계없이 모든 장소를 그리며, 예외는 스토리 플래그를 기다리는 두 곳뿐입니다. 반면 공중날기 목록에는 들어갔을 때 방문 플래그가 켜진 마을만 나옵니다.111213 지금의 Kiradex World는 40×30 크기의 마을 하나뿐이고 울타리 밖에는 아무것도 없습니다.14 그래서 정전(canon)으로 삼는 게임들의 길, 이음매, 게이트, 지도 화면을 디컴파일 결과에서 측정하고, 대조할 모델로 스타듀 밸리, 동물의 숲, 꿈꾸는 섬을 읽은 뒤, 그 숫자들을 광장 너머 네 구역과 지도 화면, 처음 도착하면 정류장이 열리는 트램을 위한 브리프로 바꿨습니다.

TL;DR

  • 걷기 한 셀은 16프레임, 약 4분의 1초입니다. Red, Crystal, Emerald는 모두 셀 하나를 16프레임에 걷고, 달리기나 자전거로는 8프레임에 갑니다. 하드웨어의 59.7헤르츠에서는 초당 3.73셀과 7.47셀입니다. Kiradex는 초당 4타일을 걷도록 설정되어 있어 휴대용 게임기보다 약 7% 빠르고, 달리기는 명목상 6.4이지만 코드의 프레임 모델로는 60헤르츠에서 6.00이어서 휴대용 게임기의 달리기보다 약 20% 느립니다.1231541617
  • 도로는 화면 2~10장 길이이고, 첫 도로는 짧고 풀숲이 가장 많습니다. 측정한 16개 도로는 진행 축을 따라 2.0화면(Emerald Route 101)에서 10.0화면(Crystal Route 32)까지입니다. 네 개의 첫 도로는 맵 면적의 14.4%~22.8%가 풀숲으로 각 게임에서 가장 많고, 트레이너가 없습니다. 양 끝이 걸어서 이어지는 아홉 도로에서는 길이 구불구불하기 때문에 가로지르는 더 긴 쪽 걸음이 도로 긴 변의 1.15~1.70배, 돌아오는 길은 0.95~1.42배입니다.5617
  • 턱이 돌아오는 길을 짧게 만듭니다. 양 끝이 걸어서 이어지는 측정 도로 아홉 개에는 모두 턱이 있고, 그 모두에서 앞 마을 쪽으로 가는 걸음이 2%~44% 짧습니다. 돌아오는 길에 밟아야 하는 풀숲 셀의 최소 개수는 0~5로, 가는 길의 4~19와 대조됩니다.5618
  • 게이트는 그림이 바뀌는 곳에 서고, 규칙을 품고 있습니다. 서로 다른 두 장소를 잇는 Red의 게이트는 모두 두 타일셋을 잇습니다. 게이트에는 배지 확인, 목마른 경비원, 그리고 10종, 30종, 50종을 잡았을 때의 보상 세 가지가 있습니다. 호연의 엔진은 이음매에서 새 타일셋을 불러오고 게이트 건물은 4개만 남겼습니다. Red에는 게이트 타일셋 맵이 27개 있습니다.8192010
  • 3세대의 이음매는 이웃 맵을 7셀(동쪽은 8셀) 그리고, 그 그림을 넘는 순간 불러옵니다. 버퍼 여백은 MAP_OFFSET 7이며, 그 이유는 “the player has 7 metatiles of view horizontally in either direction”(플레이어의 시야는 좌우 각각 7메타타일)이기 때문입니다. 동쪽은 MAP_OFFSET + 1열을 복사합니다. 넘어가면 새 맵의 보조 타일셋, 음악, 날씨를 불러오고 지명 표시를 약 3.2초 동안 밀어 넣으며, 페이드는 없습니다.91021
  • 지도 화면은 모든 장소를 보여 주고, 빠른 이동은 가 본 곳만 보여 줍니다. Emerald의 지도는 28×15칸이고 그중 158칸을 54개 장소가 씁니다. 플레이어가 지도를 열 수 있게 되면(처음에는 집 2층의 벽 지도, 나중에는 포켓내비) 방문 여부와 관계없이 모든 장소를 그리며, 스토리 플래그로 가려 둔 두 곳만 예외입니다. 마을이 공중날기 목적지가 되는 것은 들어갈 때 그 마을의 FLAG_VISITED_* 플래그가 켜졌을 때뿐이고, Red, FireRed, Crystal, 꿈꾸는 섬도 같은 종류의 방문 기록을 둡니다.11121322232425
  • Kiradex에 주는 것. 중앙 광장 너머 네 구역(바인더 거리, 초원 산책로, 호숫가, 갤러리 지구)을 중앙 광장 면적의 2.8배로 만드는 브리프입니다. 페이드 없는 열린 이음매, 앱과 서버가 함께 쓰는 8방향 보행 그래프, 16×12 지도 화면, 처음 방문하면 정류장이 열리는 트램, 코스메틱이나 퀘스트 메모로만 나오는 발견물, 그리고 스크립트나 캡처로 실행할 수 있는 인수 검사 13개를 담고 있습니다.262728

1. 도로를 측정하다

이 시리즈의 10월 3일 글 세 편은 울타리 안에 머물렀습니다. iPhone에서 만드는 픽셀 아트 세계가 타일 시스템과 RealityKit 레시피를, 픽셀 아트 인물이 수집가를, 픽셀 아트 건물이 건물과 문을 정했습니다. 거기서 나온 Kiradex World는 마을 하나입니다. 40×30 타일, 울타리 밖 12타일까지 그린 숲, 방이나 홀로 이어지는 문을 가진 건물 일곱 채, 그리고 도착 타일 하나입니다.14 이 글은 울타리 너머에 있는 것을 다루며, 앞선 글들과 같은 곳, 즉 디컴파일 결과에서 출발합니다.

아래의 포켓몬 수치는 모두 pret 디컴파일의 얕은 클론(pokered d2704a6, pokecrystal 5beda23, pokeemerald 731ad5b, pokefirered 037335f)에서 작은 Python 스크립트 여섯 개로 측정했습니다. 모두 1초 안팎으로 다시 실행되며, 각 수치를 낸 스크립트는 주석에 적었습니다.29 단위는 셀, 즉 16×16픽셀 걷기 칸 하나입니다. 3세대에서는 메타타일 하나, 1세대와 2세대에서는 블록의 4분의 1입니다. 게임보이 화면은 10×9셀(160×144픽셀)을, 게임보이 어드밴스 화면은 15×10셀(240×160픽셀)을 보여 줍니다.29 보행 모델은 모든 스크립트에서 같습니다. 한 걸음은 한 셀입니다. 턱은 그 방향으로만 넘을 수 있고 한 셀 너머에 착지하므로 이동은 두 셀입니다. Crystal에서는 타일의 한쪽 벽을 통과하는 걸음이 막히고, 모서리 턱은 두 방향 중 어느 쪽으로든 뛰어내립니다(코드는 2절에 있습니다). 이음매는 이웃 맵의 마주 보는 셀에 그 맵의 문 중 하나에서 걸어갈 수 있을 때만 셉니다. 트레이너와 다른 인물은 무시하고, 파도타기는 모델링하지 않았습니다.29

시계

세 세대 모두 걷는 속도가 같습니다. Red에서는 OverworldLoop가 반복마다 DelayFrame을 두 번 호출하고, AdvancePlayerSprite가 반복마다 시점을 2픽셀씩 8번 움직입니다(wWalkCounter는 8). 그래서 한 셀은 16프레임입니다. 자전거에서는 AdvancePlayerSprite가 반복마다 두 번 실행되어 한 셀이 8프레임입니다.1 Crystal의 StepVectors는 걷기 한 걸음을 2픽셀씩 8틱, 자전거 한 걸음을 4픽셀씩 4틱으로 정하고, 필드는 2프레임마다 1틱씩 진행합니다(MaxOverworldDelay: db 2). 이 역시 걷기는 셀당 16프레임, 자전거는 8프레임입니다.2 Emerald의 스텝 테이블은 걷기(sStep1Funcs)가 16개 항목, 달리기와 파도타기가 8개, 묘기자전거와 물살이 6개, 최고 속도의 마하자전거가 4개, 가장 빠른 것이 2개입니다. 턱 점프(JUMP_DISTANCE_FAR)는 두 셀에 32프레임이 걸리고 정점에서 12픽셀 올라갑니다(sJumpY_High).3

시계의 나머지 절반은 프레임입니다. GBATEK은 게임보이 어드밴스의 한 프레임을 280,896사이클, “ca. 59.737 Hz”(약 59.737Hz)로, Pan Docs는 게임보이의 한 프레임을 70,224도트 “@ 59.7 fps”(59.7fps)로 제시합니다.1530 셀당 16프레임이면 걷기는 초당 약 3.73셀, 달리기는 약 7.47셀입니다.17 이 글의 초 단위 수치는 224헤르츠를 280,896으로 나눈 초당 59.7275프레임을 씁니다. GBATEK의 값은 59.737이고 차이는 0.02% 미만입니다.29

Kiradex의 수집가는 tilesPerSecond = 4로 걷고, 달리기는 그 1.6배, 명목상 초당 6.4타일입니다.4 달리기 수치는 상수이지 코드가 실제로 도달하는 속도가 아닙니다. 이 시리즈의 모션 글에서 코드를 프레임 단위로 모델링해 보니, 달리기는 60헤르츠에서 초당 6.00타일, 120헤르츠에서 6.32타일이었습니다. 걸음마다 넘어선 만큼의 진행을 버리기 때문입니다.16 걷기는 휴대용 게임기의 걷기보다 약 7% 빠르고, 달리기는 60헤르츠에서 휴대용 게임기의 달리기보다 약 20% 느리며, 명목상 6.4에서도 14% 느립니다.17 걷기는 충분히 가까우므로, 휴대용 게임기의 셀로 잰 거리는 일정한 비율로 우리 타일에 환산할 수 있습니다. 도로의 소요 시간은 휴대용 게임기의 걷기로는 셀 수 × 0.27초, 우리의 걷기로는 타일 수 × 0.25초입니다.17

열여섯 개의 도로

각 게임의 첫 도로 네 개를 측정했습니다. Red의 Route 1~4, Crystal의 29~32, Emerald의 101~104, FireRed의 1~4입니다. 3세대 셀은 map.bin에서 읽고(비트 0~9는 메타타일, 10과 11은 충돌, 12~15는 높이), 각 셀의 동작은 기본 또는 보조 metatile_attributes.bin에서 찾습니다. 트레이너는 맵의 오브젝트 이벤트 가운데 trainer_type이 TRAINER_TYPE_NONE이 아닌 것입니다.6 1세대 셀은 16×16 셀마다 왼쪽 아래 8×8 타일을 타일셋의 충돌 목록, 풀 타일 $52, 턱 테이블과 대조해 읽습니다. 2세대 셀은 블록마다 4분면별로 들어 있는 충돌 바이트 네 개를 읽습니다.5

게임 도로 크기(셀) 축 방향 화면 수 걸을 수 있는 비율 풀숲, 셀 수(맵 대비 %) 턱 셀 / 턱 줄 트레이너 가로지르는 최단 걸음, 방향별(셀)
Red 1 20×36 4.0 76.8% 104 (14.4%) 42 / 10 0 남쪽 40, 북쪽 52
Red 2 20×72 8.0 55.9% 84 (5.8%) 52 / 14 0 숲으로 나뉨
Red 3 70×18 7.0 35.1% 100 (7.9%) 36 / 10 8 Pewter 방향 82, 반대 방향 84
Red 4 90×18 9.0 45.0% 60 (3.7%) 169 / 27 1 동굴로 나뉨
Crystal 29 60×18 6.0 47.7% 160 (14.8%) 35 / 13 0 동쪽 71, 서쪽 90
Crystal 30 20×54 6.0 47.6% 140 (13.0%) 21 / 6 3 남쪽 57, 북쪽 74
Crystal 31 40×18 4.0 39.3% 64 (8.9%) 13 / 5 1 서쪽 끝은 게이트
Crystal 32 20×90 10.0 48.3% 152 (8.4%) 6 / 5 8 남쪽 132, 북쪽 128
Emerald 101 20×20 2.0 59.2% 91 (22.8%) 13 / 3, 모서리 1 0 남쪽 19, 북쪽 34
Emerald 102 50×20 3.3 48.9% 143 (14.3%) 17 / 4 4 동쪽 55, 서쪽 62
Emerald 103 80×22 5.3 27.3% 92 (5.2%) 24 / 3 9 바다로 나뉨
Emerald 104 40×80 8.0 34.0% 126 (3.9%) 13 / 4 8 숲으로 나뉨
FireRed 1 24×40 4.0 62.3% 178 (18.5%) 61 / 10 0 남쪽 43, 북쪽 58
FireRed 2 24×80 8.0 40.8% 84 (4.4%) 44 / 13 0 숲으로 나뉨
FireRed 3 84×20 5.6 37.6% 117 (7.0%) 42 / 10 8 Pewter 방향 94, 반대 방향 97
FireRed 4 108×20 7.2 42.9% 84 (3.9%) 186 / 28 1 동굴로 나뉨

표의 출처: 네 디컴파일에 대한 measure_gen12_routes.py와 measure_gen3_routes.py.56 화면 수 열은 긴 변을 그 축 방향의 게임기 시야(게임보이는 10셀 또는 9셀, 게임보이 어드밴스는 15셀 또는 10셀)로 나눈 값입니다. 걸을 수 있는 비율 열은 걷는 사람이 설 수 있는 셀의 비율입니다. 턱 셀은 1세대와 3세대에서는 점프 셀, 2세대에서는 가장자리 셀입니다. 걸음은 문에서 도달할 수 있는 이음매 셀 사이를 잽니다. 나뉜 도로란 숲, 동굴, 게이트, 바다가 두 반쪽 사이에 있어서 맵 안에 이음매에서 이음매로 가는 걸음이 없는 도로입니다.29

초기 포켓몬 도로 16개의 막대그래프. 각 맵의 긴 변을 셀로 나타내고, 방향별 가로지르는 최단 걸음을 점으로, 걸치는 게임기 화면 수를 라벨로 붙였다. Emerald Route 101의 2.0화면부터 Crystal Route 32의 10.0화면까지이며, 축은 셀과 걷는 초.

긴 축 방향의 도로 길이와 방향별 가로지르는 최단 걸음. 두 도로 스크립트의 출력으로 figures/make_figures.py가 그렸습니다.

이 표에서 다섯 가지가 드러납니다.

도로는 화면 2~10장이고, 첫 도로는 짧습니다. Emerald Route 101은 게임보이 어드밴스 화면 두 장 높이이고, Crystal Route 32는 게임보이 화면 열 장 높이입니다. 각 게임의 첫 도로는 화면 2~6장입니다.56 셀로 세면 측정한 도로의 긴 변은 20~108셀입니다.6

가로지르는 더 긴 쪽 걸음은 긴 변의 1.15~1.70배입니다. 16개 도로 중 아홉 개는 끝에서 끝까지 걸을 수 있습니다. 그 아홉 개에서 더 긴 방향의 최단 걸음을 도로의 긴 변과 비교하면 다음과 같습니다. Emerald Route 101 북쪽 방향이 34 대 20으로 1.70, Crystal Route 29가 90 대 60으로 1.50, Crystal Route 32가 132 대 90으로 1.47, FireRed Route 1이 58 대 40으로 1.45, Red Route 1이 52 대 36으로 1.44, Crystal Route 30이 74 대 54로 1.37, Emerald Route 102가 62 대 50으로 1.24, Red Route 3이 84 대 70으로 1.20, FireRed Route 3이 97 대 84로 1.15입니다.5617 돌아오는 길은 더 곧아서 긴 변의 0.95~1.42배입니다. Emerald Route 101이 19 대 20, Crystal Route 30이 57 대 54, FireRed Route 1이 43 대 40, Emerald Route 102가 55 대 50, Red Route 1이 40 대 36, FireRed Route 3이 94 대 84, Red Route 3이 82 대 70, Crystal Route 29가 71 대 60, 그리고 Crystal Route 32가 128 대 90입니다. Route 32는 한쪽 벽 때문에 어느 방향으로든 먼 길로 돌아가게 됩니다.5617 비가 1 아래라고 해서 공간을 질러가는 것은 아닙니다. 20셀 맵의 첫 행 이음매 셀에서 마지막 행 이음매 셀까지 걸으면 19걸음이므로, 완전히 곧은 도로는 0.95가 됩니다.17 제 해석으로는, 도로의 크기를 정할 때 기준으로 삼을 수치는 가는 쪽입니다. 경계 상자가 아니라 구불구불한 걸음 그 자체입니다.

여정이 진행될수록 풀은 줄어듭니다. 풀숲은 도로 맵의 3.7%~22.8%를 차지합니다. 네 개의 첫 도로인 Red 1, Crystal 29, Emerald 101, FireRed 1은 각 게임의 네 도로 가운데 풀숲이 가장 많아 14.4%, 14.8%, 22.8%, 18.5%입니다. 두 번째 도로는 4.4%~14.3%, 세 번째와 네 번째는 3.7%~8.9%입니다.56 대신 설 수 있는 땅을 기준으로 세면 비율이 커지고, 경향은 평균으로만 성립합니다. 첫 도로는 18.8%~38.4%가 풀숲이고 나머지 열두 개는 8.2%~29.2%이며, Red Route 3(22.6%)은 발밑 기준으로 Red Route 1(18.8%)보다 풀숲이 많습니다. Emerald Route 101에서는 걸을 수 있는 237셀 중 91셀, 38.4%가 풀숲입니다.5617

첫 도로에는 트레이너가 없습니다. Red 1, FireRed 1, Emerald 101, Crystal 29에는 한 명도 없습니다. 트레이너는 두 번째나 세 번째 도로부터 나오며, Emerald Route 102에 4명, Crystal Route 30에 3명, Red와 FireRed의 Route 3에 8명이 있습니다.56 이 도로들에서 트레이너의 시야는 0~7셀이고, Emerald Route 103의 아홉 명은 1~5셀, Route 104의 여덟 명은 0~7셀을 봅니다.6

인카운터 판정은 짧은 유예 뒤에 대략 아홉 걸음에 한 번입니다. Emerald는 플레이어가 이음매로든 문으로든 맵에 들어온 직후와 배틀이 끝난 뒤의 처음 네 걸음은 판정하지 않습니다. CheckStandardWildEncounter는 sWildEncounterImmunitySteps < 4인 동안 그 걸음을 세기만 하고, 인카운터가 일어날 때마다 다시 셉니다. 맵을 불러올 때와 배틀이 시작될 때도 다시 셉니다. 그 뒤로는 인카운터 셀에 들어가는 걸음마다 판정합니다. 다른 동작의 셀로 옮기는 걸음에서는 40% 확률로 판정을 건너뛰고, 그다음 Random() % 2880 < rate × 16입니다. Route 101~104는 모두 rate 20이므로 보정 없는 판정은 2,880분의 320, 걸어서 한 걸음당 11.1%입니다. 자전거, 피리, 순결의부적, 일부 선두 포켓몬의 특성은 그 전에 비율을 바꿉니다.31 FireRed는 하한과 오르막을 더합니다. 인카운터 뒤와 맵에 들어갈 때 인카운터 셀에서 8 − rate/10걸음(Route 1~4의 rate 21이면 6걸음)의 쿨다운이 있고, 그 걸음마다 5% 판정에 걸리면 쿨다운을 끝내지 않은 채 그 한 걸음만 인카운터를 시도할 수 있습니다. 다음으로 새 동작에서의 60% 판정, 그다음 1,600분의 rate × 16, 즉 21%이며, 판정에 실패할 때마다 rate만큼 커지는 가산치(encounterRateBuff)가 붙습니다.32 저는 이 유예와 하한과 오르막을 가뭄과 홍수를 모두 짧게 유지하는 장치로 읽습니다. Kiradex에는 야생 배틀이 없으므로 이 수치는 리듬으로서만 의미가 있습니다. 처음 몇 걸음이 지나면, 첫 도로는 풀숲을 아홉 걸음쯤 걸을 때마다 눈여겨볼 것을 하나 내놓는다는 뜻입니다.

세계에서 길이 차지하는 몫

게임 도로 맵 수 도로 셀 수 마을 맵 수 마을 셀 수 도로 대 마을
Red 25 31,500 11 11,880 2.65
Crystal(성도와 관동) 54 49,880 23 25,380 1.97
Emerald(육지 도로) 41 87,787 16 23,700 3.70
FireRed(Sevii 제도 포함) 57 98,451 19 25,470 3.87

길은 마을 면적의 2~4배입니다.33 Emerald의 바다 도로 11개를 더하면 45,600셀이 늘어납니다.33 이 비는 맵을 어떻게 분류하느냐에 달려 있고, 게임마다 분류 방식이 다릅니다. Red는 맵 ID와 이름으로, Crystal은 환경으로(예를 들어 ROUTE 환경에는 알프의 유적 바깥이 포함됩니다), Emerald와 FireRed는 map_type으로 분류하며, FireRed의 도로에는 Sevii 제도가 포함되고 Emerald의 도로에서는 바다가 빠집니다.33 Emerald의 지도 화면에서는 같은 세계가 도로 129칸 대 마을 22칸, 5.9 대 1로 읽힙니다. 마을은 크기와 관계없이 한두 칸만 차지하기 때문입니다. 마을과 도시 16곳 가운데 열 곳은 한 칸, 여섯 곳은 두 칸입니다.341117

Route 1, 세 가지 방식

Red, FireRed, Crystal은 같은 생각을 세 가지 해상도로 그리며, Route 1이 가장 깔끔한 비교 대상입니다. Red의 Route 1은 10×18블록, 20×36셀, 게임보이 화면 네 장 높이이고, 울타리 기둥과 나무 줄 사이에 남향 턱 10줄, 모두 42셀이 있으며 풀은 104셀입니다.5 1세대 셀 모델을 확인하려고 이 맵 하나만 블록셋에서 두 배 크기로, 16픽셀 격자와 함께 렌더링했습니다. 그러자 서쪽 나무 줄 바깥에 폭 3셀의 빈 땅이 드러났는데, 두 이음매에 모두 닿아 있으면서도 어느 마을의 문에서도 갈 수 없었습니다. 탐색이 이웃 마을의 문에서 가로지를 지점을 시작하는 이유가 이것입니다.5 1세대 모델은 셀마다 8×8 타일 하나, 왼쪽 아래 것만 읽습니다. 확인은 이 렌더링을 눈으로 본 범위에서만 했고, 물과 땅의 쌍 같은 타일 쌍 충돌은 모델링하지 않았습니다.29

FireRed의 Route 1은 24×40셀이며, 더 커진 화면에서도 여전히 화면 네 장 높이입니다. 턱은 61셀, 풀은 178셀로 맵의 18.5%입니다. 리메이크는 화면 수로 본 길이를 유지하고, 맵을 각 방향으로 4셀씩 넓히고, 턱을 늘렸습니다.6 Pallet의 현관에서 Viridian의 포켓몬센터까지는 94셀, 25초이고, 반대 방향은 76셀입니다.7 Crystal의 첫 도로인 Route 29는 60×18셀, 게임보이 화면 여섯 장 너비이며 풀은 14.8%이고 트레이너가 없습니다. New Bark 쪽에서 Cherrygrove 쪽으로 가로지르면 90셀, 돌아오면 71셀입니다.5

2. 문에서 문으로, 그리고 돌아오는 길

도로 자체의 길이는 여정의 일부일 뿐입니다. 플레이어가 느끼는 것은 구간입니다. 한 건물에서 나와 마을을 지나고, 도로와 다음 마을을 가로질러, 다음 건물로 들어가기까지입니다. measure_travel.py는 그 전체 경로를 (맵, 셀) 쌍 위에서 이음매, 워프, 턱을 거쳐 탐색합니다. 출발점은 첫 문 아래 셀, 도착점은 마지막 문이며, 그 문으로 들어서는 한 걸음까지 셉니다.7

게임 출발 도착 셀 걷기 달리기 지나는 맵
Emerald Littleroot, 플레이어의 집 Oldale 포켓몬센터 58 15.5초 7.8초 마을, 도로, 마을
Emerald Oldale 포켓몬센터 Petalburg 포켓몬센터 87 23.3초 11.7초 마을, 도로, 도시
Emerald Petalburg 포켓몬센터 Rustboro 포켓몬센터 250 67.0초 33.5초 도시, 도로, 숲, 도로, 도시
FireRed Pallet, 플레이어의 집 Viridian 포켓몬센터 94 25.2초 12.6초 마을, 도로, 도시
FireRed Viridian 포켓몬센터 Pewter 포켓몬센터 267(풀베기 후 156) 71.5초(41.8초) 35.8초 숲의 게이트 두 곳을 지남
FireRed Pewter 포켓몬센터 Route 4 포켓몬센터 150 40.2초 20.1초 도시, 도로, 도로
FireRed Route 4 포켓몬센터 Cerulean 포켓몬센터 314 84.1초 42.3초 동굴의 세 층을 지나며, 그중 한 층은 두 번

걷기 초 수치는 셀 수 × 16프레임을 59.7275헤르츠로 나눈 값입니다. 달리기는 최소 프레임 수를 찾는 두 번째 탐색으로, 셀당 8프레임이지만 턱 점프는 여전히 32프레임입니다. 점프는 어느 걸음걸이에서든 같은 32프레임짜리이기 때문입니다. 위의 일곱 구간 가운데 턱을 뛰어내리는 것은 동굴 구간 하나뿐이고 그것도 한 번이어서, 2,512프레임이 아니라 2,528프레임이 됩니다. “풀베기 후” 수치는 Route 2의 풀베기 나무 다섯 그루를 없앤 같은 탐색이며, 이렇게 하면 ROUTE2_EAST_BUILDING을 지나는 동쪽 길이 열립니다. 페이드와 배틀은 세지 않았습니다.7 탐색의 단순화 가운데 동굴 구간에서 가장 크게 작용하는 것이 두 가지 있습니다. 3세대의 높이를 두 경우(같은 높이, 또는 어느 한쪽이 0이나 15)로 줄인 것, 그리고 워프를 도착했을 때가 아니라 밟았을 때 발동시킨 것입니다. 그래서 1F, B1F, B2F, 다시 B1F를 지나는 동굴 경로의 314셀은 표에서 가장 불확실한 수치입니다.29

Pokémon Emerald와 FireRed에서 측정한 문에서 문까지 일곱 구간을 가는 길과 돌아오는 길로 나누어 걷는 초와 셀 수로 나타낸 가로 막대그래프. 양방향을 모두 잰 다섯 구간에는 돌아오는 막대가 있다. 첫 두 구간은 가는 길 15.5초와 25.2초, 돌아오는 길 11.3초와 20.4초. 그 아래에는 초당 4타일 기준 Kiradex 브리프 목표를 나타낸 범위 막대 세 개.

문에서 문까지, 가는 길과 측정한 경우 돌아오는 길. 브리프의 목표를 정전 옆에 나란히 두었습니다. travel.json으로 figures/make_figures.py가 그렸습니다.

첫 구간은 걸어서 15~25초입니다. 집 문에서 다음 마을의 포켓몬센터까지 Emerald는 58셀, 15.5초이고 FireRed는 94셀, 25.2초입니다.7 1분에 이르는 구간(Emerald의 250셀, FireRed의 267셀과 314셀)은 숲이나 동굴을 지납니다. 제 해석으로는 그것은 길이 아니라 던전이며, 던전은 그 자체로 하나의 장소 종류입니다.

돌아오는 길은 더 짧습니다. Oldale 포켓몬센터에서 Littleroot의 플레이어 집까지는 가는 길 58셀에 비해 42셀입니다. Viridian에서 Pallet은 94에 비해 76, Petalburg에서 Oldale은 87에 비해 81, Rustboro에서 Petalburg는 250에 비해 196, Pewter에서 Viridian은 267에 비해 254입니다.7

비전머신은 이미 지나쳐 온 게이트를 통과하는 지름길입니다. Route 2의 풀베기 나무를 없애면 Viridian에서 Pewter까지가 267셀이 아니라 156셀이 되고, 길은 숲 대신 Route 2의 동쪽 건물을 지납니다.7

호연의 첫 세 구간

Emerald는 마을과 마을 사이에 무엇이 있느냐는 질문에 세 가지 다른 답을 내놓으며 시작합니다. 측정해 보면 그 설계가 읽힙니다.

Route 101은 양 끝에 현관이 있는 통로입니다. 20×20셀, 화면 두 장 높이이며 풀숲은 22.8%, 설 수 있는 237셀 중 91셀입니다. 남향의 4셀짜리 턱 세 줄이 도로를 가로지릅니다. Littleroot에서 북쪽으로 걸으면 34셀이고 풀 셀을 적어도 10개 지납니다. Oldale에서 남쪽으로 걸으면 19셀이고, 턱을 뛰어내리면 풀을 전혀 밟지 않을 수 있습니다. 플레이어의 현관에서 Oldale 포켓몬센터까지는 58셀, 걸어서 15.5초입니다.6187

Route 102는 더 넓고 첫 트레이너가 있습니다. 50×20셀, 화면 3.3장 너비이며 풀은 14.3%이고, 시야 2~3셀의 트레이너 4명, 물 셀 26개짜리 연못, 턱 셀 17개가 있습니다. Petalburg는 −10의 오프셋으로 붙어 있어서 도로의 20행은 Petalburg의 10~29행과 마주합니다. 포켓몬센터에서 포켓몬센터까지 Oldale에서 Petalburg는 87셀, 23.3초이고, 돌아오는 길은 81셀입니다.67

Route 104는 두 쪽으로 나뉜 도로입니다. 40×80셀, 화면 여덟 장 높이이며 4분의 1이 물이고, 맵 안에는 세 이음매를 잇는 걸음이 없습니다. 남쪽 절반은 Petalburg Woods의 남쪽 입구로 이어지며 Petalburg 이음매에서 51셀입니다. 북쪽 절반은 숲의 북쪽 출구로 이어지며, Rustboro 이음매에서 출구의 두 출입구 셀 중 가까운 쪽까지 60셀(다른 쪽까지는 61셀)입니다. Petalburg 포켓몬센터에서 Rustboro 포켓몬센터까지는 다섯 맵(도시, 도로, 숲, 도로, 도시)을 지나 250셀, 걸어서 67초이고, 돌아오는 길은 196셀입니다.67

세 도로에서 달라지는 것은 분모입니다. 첫 도로는 20초가 안 되는 걸음이고, 트레이너가 없으며, 돌아오는 길에는 풀이 없습니다. 세 번째는 던전을 지나는 1분짜리 걸음입니다. 제 해석으로는, 이 게임은 플레이어가 걷는 법을 익힌 뒤에야 거리를 씁니다.

턱은 집을 향한다

초기 도로 아홉 개의 덤벨 차트. 앞 마을에서 멀어지는 가는 길과 돌아오는 길의 최단 걸음을 셀로 나타낸다: Red Route 1 52와 40, FireRed Route 1 58과 43, Emerald Route 101 34와 19, Emerald Route 102 62와 55, Crystal Route 29 90과 71, Crystal Route 30 74와 57, Red Route 3 84와 82, FireRed Route 3 97과 94, Crystal Route 32 132와 128. 아래에는 측정한 도로 네 개에서 방향별로 밟아야 하는 풀숲 셀의 최소 개수를 짝지은 막대.

양 끝이 걸어서 이어지는 측정 도로 전부의 가는 길과 돌아오는 길, 그리고 방향별 최소 풀 셀 수. 도로 스크립트의 출력과 grass_paths.txt로 figures/make_figures.py가 그렸습니다.

양 끝이 걸어서 이어지는 측정 도로는 아홉 개 모두 턱이 있고, 그 모두에서 앞 마을 쪽으로 가는 걸음이 더 짧습니다. Red Route 1은 가는 길 52셀에 비해 돌아오는 길 40셀로 23% 짧고, FireRed Route 1은 58에 비해 43으로 26%, Emerald Route 101은 34에 비해 19로 44%, Emerald Route 102는 62에 비해 55로 11%, Crystal Route 29는 90에 비해 71로 21%, Crystal Route 30은 74에 비해 57로 23%입니다. Red Route 3은 84에 비해 82, FireRed Route 3은 97에 비해 94, Crystal Route 32는 132에 비해 128로 각각 2%~3%입니다. Route 32의 4셀 차이는 모서리 턱에서 옆으로 한 번 뛰어내리는 데서 나오며, 돌아오는 길에서 뛰어내리는 것은 그 한 번뿐입니다.5617 첫 도로의 턱은 모두 같은 방향을 향합니다. Red Route 1의 10줄 42셀, FireRed Route 1의 10줄 61셀, Emerald Route 101의 13셀(4셀짜리 줄 셋과 모서리 셀 하나)은 모두 남향이고 모서리는 남동향이며, 각 맵에서 그것은 출발한 마을로 돌아가는 방향입니다.56

턱은 돌아오는 길에서 풀도 걷어 냅니다. 걸음 수가 아니라 밟는 풀숲 셀 수를 최소로 하는 두 번째 탐색에 따르면, Red Route 1을 북쪽으로 걷는 사람은 적어도 풀 셀 15개를 지나야 하지만 남쪽으로는 4개뿐이며, 그 모두가 Pallet 옆 입구에 있습니다. FireRed Route 1은 19 대 5, Emerald Route 101은 10 대 0, Emerald Route 102는 가는 길 4 대 돌아오는 길 0입니다.18 Bulbapedia의 관동 Route 1 공략도 같은 내용을 문장으로 말합니다. 남쪽으로 갈 때 트레이너는 “can either hop down ledges to completely avoid any contact with wild Pokémon”(턱을 뛰어내려 야생 포켓몬과의 접촉을 완전히 피할 수도 있고) 아니면 “the grass patches, the required path for northbound travel”(북쪽으로 갈 때 반드시 지나야 하는 풀숲)을 지날 수도 있다는 것입니다.35 이것은 탐색을 교차 확인하려고 한 번만 쓴 위키 페이지이며, 탐색은 Pallet 옆 입구를 빼면 이 설명과 일치합니다. 그 입구는 폭 2셀, 풀 4행 깊이여서 셀 모델에서는 남쪽으로 가는 모든 걸음이 거기서 행마다 1셀씩, 풀 셀 4개를 지납니다. 턱은 도로의 다른 풀은 모두 돌아가게 해 주지만, 정말 전부는 아닙니다.18

2세대 수치에는 각각 한 가지씩 단서가 필요합니다. Crystal의 충돌은 32픽셀 블록마다 4바이트, 4분면마다 1바이트이며, 스크립트는 이것이 행 우선 순서(왼쪽 위, 오른쪽 위, 왼쪽 아래, 오른쪽 아래)로 놓인다고 가정합니다. tilecoll 매크로가 순서를 밝히지 않기 때문입니다.29 2세대의 COLL_HOP_* 바이트는 그 너머 셀이 아니라 플레이어가 서는 가장자리 셀을 표시합니다. 이는 probe_gen2_ledges.py가 Route 30의 HOP_DOWN 셀 21개 모두의 아래에서 WALL 셀을 찾아내 확정했습니다. 가장자리라는 해석은 Route 29와 30에서만 확인했습니다.529 Crystal에는 한쪽 벽도 있습니다. COLL_RIGHT_WALL부터 COLL_UP_LEFT_WALL까지의 충돌 바이트는 땅이지만, GetMovementPermissions는 그런 타일에서 벽이 있는 쪽으로 나가는 걸음도, 그쪽에서 들어오는 걸음도 거부합니다. 네 도로 중 이것이 있는 유일한 도로인 Route 32(41셀, 모두 UP_WALL)에서는, 이를 무시하는 탐색이 찾는 양방향 110셀의 최단 걸음이 가는 길 132셀, 돌아오는 길 128셀로 늘어납니다. 그 모서리 턱 HOP_DOWN_RIGHT와 HOP_DOWN_LEFT는 평범한 걸음이 거부되면 플레이어가 향한 방향에 따라 아래나 옆으로 뛰어내리며, 돌아오는 길은 그중 하나를 옆으로 뛰어내립니다. Red에는 한쪽 벽이 없습니다. Red의 다른 이동 규칙인 타일 쌍 충돌은 양방향으로 작동하고 동굴과 숲 타일셋에만 등록되어 있으며, 여기서 측정한 맵은 그중 어느 것도 쓰지 않습니다.5 또 탐색은 턱을 두 셀 이동으로 셉니다. 이는 3세대의 32프레임 점프와 일치하며, 1세대와 2세대에서는 가정입니다.293

데이터가 보여 주는 것은 결과이지 의도가 아닙니다. 턱을 돌아오는 길을 줄이도록 배치했다는 개발자의 발언은 찾지 못했고, 측정한 모든 도로에서 실제로 그렇다는 것만 알 수 있습니다.29 제가 여기서 끌어내는 규칙은, 턱은 돌아오기 위한 일방통행 지름길이지 결코 앞길을 막는 벽이 아니라는 것입니다.

높이의 문제

이 발견은 지난 글과 어색하게 맞물립니다. 픽셀 아트 건물의 바탕이 된 건물 조사 자료는 턱을 단호히 거부했습니다. “No ledges to jump, no climbing, no isometric”(뛰어내릴 턱 없음, 기어오르기 없음, 아이소메트릭 없음). 그리고 그 글은 빌드가 하지 않는 일 가운데 하나로 일방통행 턱을 꼽습니다.3637 이번 조사 자료는 턱을 정전의 귀갓길 지름길로 측정합니다. 둘은 사실을 두고 충돌하는 것이 아닙니다. 수집하는 마을이 그 효과를 얻는 데 높이가 필요한지를 두고 의견이 갈립니다. 그 결정은 이 프로그램의 다음 글, 높이와 턱과 다리를 다룰 글의 몫이며, 아직 공개되지 않았습니다. 거기서 정해질 때까지 7절의 브리프는 턱을 높이 글로 미루고, 짧은 귀갓길은 생울타리 문에서 얻습니다. 초원 산책로에 있는, 호수 쪽에서만 열리는 문입니다. 높이 없이 같은 일방통행 귀갓길 지름길을 만듭니다.26

3. 이음매, 게이트, 지도 화면

포켓몬의 필드는 하나의 커다란 맵이 아닙니다. 저마다 크기, 타일, 음악을 가진 작은 맵 여러 개가 변과 변으로 이어져 있어서, 끊김 없이 다음 맵으로 걸어 들어갈 수 있습니다. 이 결합 방식이 이 절의 거의 모든 것을 결정합니다. 길 위 어디에 건물을 세워야 하는지, 왜 리메이크에는 그런 건물이 적은지, 그리고 지도 화면이 무엇을 알 수 있는지까지입니다.

1세대와 2세대: 여백에 복사되는 띠

Red의 연결은 맵 헤더의 한 줄로, 방향, 이웃 맵, 블록 단위 오프셋을 지정합니다. Route 1의 연결은 connection north, ViridianCity, VIRIDIAN_CITY, -5이고, 매크로는 이웃 맵 블록의 어느 띠를 현재 맵의 버퍼에 복사할지 미리 계산합니다.38 버퍼 wOverworldMap은 맵의 사방에 MAP_BORDER EQU 3블록, 즉 6셀의 여백을 둡니다. 연결은 그 여백을 이웃 맵에서 가장 가까운 블록 3행 또는 3열로 채우고, CheckMapConnections는 플레이어의 좌표가 −1이나 맵의 너비 또는 높이를 넘을 때 맵을 바꿉니다.39

띠는 블록 번호로 복사되어 그때 불러와져 있는 블록셋으로 그려지므로, 두 맵이 이음매에서 만나려면 타일셋을 공유해야 합니다. Red의 데이터는 이를 지킵니다. 연결 줄 78개 가운데 76개가 같은 타일셋의 맵끼리 잇습니다. 예외 두 개는 Route 22와 Route 23(OVERWORLD 대 PLATEAU)이며, 헤더 파일은 두 줄 모두에 “; unnecessary”(불필요)라고 표시해 두었습니다.840 Crystal에는 연결 줄이 142개 있습니다. 138개는 같은 타일셋끼리 잇고(예외는 Goldenrod와 Route 35, Route 32와 Route 33으로 Johto 대 Johto Modern), 92개는 한 맵 그룹 안에 머뭅니다.841

3세대: 이웃 맵 7셀(동쪽은 8셀), 그림은 넘는 순간에

3세대의 연결은 맵의 map.json에 있는 map, offset, direction 항목입니다. Emerald에는 상하좌우 항목 134개와 다이빙 및 부상 항목 14개가 있고, 134개 모두에 오프셋 부호를 뒤집은 역방향 항목이 짝지어 있습니다.8 디컴파일 커뮤니티가 쓰는 맵 에디터 Porymap은 이 기능을 세 문장으로 설명합니다. “Maps can be connected together so that the player can seamlessly walk between them”(맵끼리 연결해 플레이어가 끊김 없이 오갈 수 있게 할 수 있다), “A connection has a direction, offset, and destination map”(연결은 방향, 오프셋, 목적지 맵을 가진다), 그리고 “Connections are one-way, which means that you must keep the two connections in sync between the two maps.”(연결은 단방향이므로 두 맵 사이의 두 연결을 동기화해 두어야 한다).42

엔진은 현재 맵을 각 변에 MAP_OFFSET 7셀의 여백을 둔 버퍼에 복사합니다(동쪽은 8셀입니다. 버퍼가 맵 너비에 MAP_OFFSET_W, 즉 2 × 7 + 1을 더한 크기이기 때문입니다). 헤더는 그 이유를 주석으로 밝힙니다. “the player has 7 metatiles of view horizontally in either direction.”(플레이어의 시야는 좌우 각각 7메타타일). FillSouthConnection과 그 형제 함수들은 이웃 맵의 7행 또는 7열(동쪽은 8열)을 연결의 오프셋 위치에 맞춰 그 여백에 복사하며, 범위는 이웃 맵 자신의 너비까지입니다(FillNorthConnection은 오프셋에 MAP_OFFSET을 더한 위치에서 시작해, 들어맞는 범위에서 이웃 맵의 너비만큼 복사합니다). 버퍼 전체는 최대 MAX_MAP_DATA_SIZE 10240셀입니다.9 연결이 없는 곳의 여백은 레이아웃의 2×2 경계 패턴이 되며, MAPGRID_IMPASSABLE과 OR되어 절대 걸을 수 없습니다(GetBorderBlockAt).9

20×20셀 도로와 그 북쪽에 오프셋 0으로 연결된 너비 20셀 이웃 맵에 대한 3세대 맵 버퍼의 모식도. 가운데에 도로가 있고 서쪽, 북쪽, 남쪽에 7셀, 동쪽에 8셀의 여백이 있다. 이웃 맵의 7행이 북쪽 여백을 도로의 20열만큼만 채우고, 네 모서리와 다른 여백에는 통과할 수 없는 경계 패턴이 있으며, 15×10셀 화면이 북쪽 변에 걸쳐 있다.

이음매에서 버퍼가 담는 것의 모식도. 셀 하나를 한 칸으로 하고, MAP_OFFSET, FillNorthConnection, Route 101의 20×20 레이아웃과 그 북쪽에 오프셋 0으로 붙은 Oldale의 너비 20 레이아웃에서 치수를 잡았습니다. figures/make_figures.py가 그렸으며 게임 그림은 쓰지 않았습니다.

이웃 맵의 띠는 플레이어가 넘어갈 때까지 현재 맵의 타일셋으로 그려집니다(DrawMetatileAt은 지금 서 있는 맵의 기본 및 보조 세트를 받습니다). 넘어가면 LoadMapFromCameraTransition이 호출되어 새 맵의 전환 시 스크립트를 실행하고, 그 맵의 보조 타일셋과 팔레트만 불러오고, 음악과 날씨를 바꾸고, 지명 표시를 띄웁니다. 페이드는 없습니다.10 그래서 기본 타일셋이 다른 연결 쌍은 하나도 없습니다. Emerald 134개 중 0개, FireRed 120개 중 0개입니다. 보조 타일셋이 다른 것은 Emerald에서 38개, FireRed에서 34개이며, 각각 24개에서는 여백에 들어가는 이웃의 띠(7셀, 동쪽은 8셀이고, 엔진처럼 버퍼를 벗어나는 부분은 잘라 냄)가 기본 메타타일만 써서 어느 쪽에서 보든 제대로 그려집니다.8

오프셋은 흔합니다. Emerald의 연결 134개 중 36개, FireRed의 120개 중 68개가 0이 아닙니다. FireRed의 Route 1은 Viridian의 48셀 너비에서 12셀 안쪽에 놓입니다.8 FireRed에서는 상호성이 완전히 보편적이지는 않습니다. 120개 항목 중 112개가 상호적이고, 나머지 8개 중 6개는 성벽으로 둘러싸인 도시 때문입니다. Saffron City는 Route 5~8에 한쪽으로만 연결되어 있지만, 그 도로들은 Saffron이 아니라 별도의 SAFFRON_CITY_CONNECTION 맵에 연결됩니다. 마지막 두 개는 Sevii 제도의 시제품 맵입니다.8 저는 이 Saffron 배치를 그리기 위한 요령으로 읽습니다. 이 연결은 도로 끝 너머로 도시 성벽을 그리려고 존재하며, 들어가는 길은 게이트 네 곳이고, Red에서는 그 경비원들이 음료를 받기 전까지 플레이어를 돌려보냅니다.819 연속되어 보여야 하면서도 관문이 필요한 곳에서, 3세대는 여백에 이웃을 그리고 문은 건물 안에 둡니다.

show_map_name이 설정된 맵으로 이음매를 넘으면 그 장소의 이름이 미끄러져 들어옵니다. 표시 태스크는 31프레임을 기다렸다가, 프레임당 2픽셀로 40픽셀을 미끄러져 들어오고(20프레임), 타이머가 120을 넘을 때까지 머문 뒤(121프레임), 미끄러져 나갑니다(20프레임). 합쳐서 약 190프레임, 3.2초입니다.21 태스크의 각 상태는 임계값으로 셌기 때문에, 각 상태가 제가 센 것보다 한 프레임 길거나 짧을 수 있습니다.29

게이트: 그림이 바뀌는 곳

Red에는 GATE 또는 FOREST_GATE 타일셋을 쓰는 맵이 27개 있습니다. Route 11, 12, 15, 16, 18의 2층짜리 게이트(맵 10개), Route 2, 5, 6, 7, 8의 단층 게이트, Route 22 게이트, Safari Zone 게이트와 그 휴게소 4채, Underground Path 입구 4곳, 그리고 Viridian Forest 게이트 2곳입니다.8 서로 다른 두 장소를 잇는 Red의 게이트는 모두 두 타일셋을 잇습니다. OVERWORLD에서 FOREST(Viridian Forest, Safari Zone)로, UNDERGROUND(지하 통로 입구 네 곳)로, 또는 PLATEAU(Route 22에서 Route 23)로. Red의 연결이 거의 만들지 않는 결합입니다.8

가장 분명한 사례는 Route 2입니다. Red에서는 20×72셀, FireRed에서는 24×80셀이며 끝에서 끝까지 걸을 수 없습니다. 남쪽 절반과 북쪽 절반은 Viridian Forest를 통해서만 만나는데, Red에서 이 숲은 OVERWORLD가 아니라 FOREST 타일셋으로 그려지고 게이트 두 곳을 통해 들어갑니다.58 FireRed에서 Viridian 포켓몬센터부터 Pewter 포켓몬센터까지는 남쪽 게이트, 숲, 북쪽 게이트를 지나 267셀입니다.7 여기서 세 가지 해석이 나오며, 이는 데이터의 해석이지 개발자의 발언이 아닙니다.

  1. 게이트는 그림이 바뀌는 곳입니다. 1세대 이음매는 이웃의 블록을 현재 블록셋으로 그리므로, 두 맵이 이음매에서 만나려면 타일셋을 공유해야 하고, Red는 연결 78개 중 76개에서 이를 지킵니다. 숲 타일셋으로 그린 숲에는 그래서 문이 필요하고, 게이트가 그 문입니다.388
  2. 게이트는 규칙이 머무를 수 있는 곳입니다. Saffron의 게이트 네 곳은 음료를 건넬 때까지 플레이어를 돌려보냅니다(TEXT_ROUTE5GATE_GUARD_GEE_IM_THIRSTY, BIT_GAVE_SAFFRON_GUARDS_DRINK). Route 22 게이트는 BIT_BOULDERBADGE를 확인합니다.19 그리고 게이트 세 곳은 수집에 보상합니다. 오박사의 조수들은 잡은 종의 수(wPokedexOwned에 대한 CountSetBits)가 Route 2 게이트에서 10, Route 11 게이트 2층에서 30, Route 15 게이트 2층에서 50에 이르면 도구를 줍니다.20
  3. 게이트는 사람이 있는 쉼표입니다. Route 2 게이트에는 오박사의 조수와 소년이 있습니다. 걸음은 페이드 뒤 새로운 장소에서 다시 이어집니다.43

리메이크는 엔진에 따라 갈립니다. Crystal에는 환경이 GATE인 맵이 25개 있고, 그중 19개는 서로 다른 맵 그룹의 맵끼리, 7개는 서로 다른 타일셋끼리 잇습니다.8 FireRed는 관동의 게이트를 유지합니다. 실내 맵 8개가 서로 다른 두 야외 맵으로 이어지고(Viridian Forest 한 쌍, Saffron 입구 네 곳, Route 22의 북쪽 입구, Safari 입구), 13개는 한 야외 맵의 서로 떨어진 두 쪽에 문을 둡니다. 그중에는 2층짜리 도로 게이트 다섯 곳과 Route 2의 동쪽 건물이 있습니다.8 호연은 게이트를 거의 없앱니다. Emerald에서 서로 다른 두 야외 맵으로 이어지는 실내 맵은 2개뿐이고(Mt. Pyre 1층과 Safari Zone 입구), 한 야외 맵의 두 쪽에 문을 둔 것이 5개이며 그중에 Cycling Road 역사 두 곳이 있습니다. 도로와 마을은 열린 이음매로 만납니다.8 건물로 세면 Emerald의 게이트는 4개(Cycling Road 역사 두 곳, Safari Zone 입구, Battle Frontier 게이트)이고, FireRed는 14개, Red는 게이트 타일셋 맵이 27개입니다.8 제 해석이며, 어디까지나 해석입니다. 호연이 게이트를 없앨 수 있었던 것은 엔진이 넘어가는 순간 새 보조 타일셋을 불러오므로, 다른 그림으로 그린 마을과 도로가 사이에 건물 없이 만날 수 있기 때문입니다.10

지도 화면과 공중날기

Emerald의 지방 지도는 28×15칸(MAP_WIDTH 28, MAP_HEIGHT 15), 모두 420칸의 격자입니다. 그중 158칸, 37.6%가 어떤 장소에 속하며 54개 구역으로 나뉩니다. 도로 34개, 마을과 도시 16개, 기타 4개입니다. 도로가 129칸, 마을이 22칸을 차지합니다.11 region_map_sections.json의 항목 213개 중 95개가 격자 위 직사각형을 가집니다. 그중 49개는 한 칸이고, 가장 큰 것은 4×3(Route 124와 그 해저 쌍둥이), Slateport는 1×2, Mauville은 2×1입니다.11 이 증거로 보면, 지도 화면은 이름 붙은 직사각형으로 이루어진 성긴 격자이고 대부분의 장소는 한 칸입니다.

공중날기는 화면과 걸음이 만나는 곳입니다. Emerald의 공중날기에는 여섯 번째 배지(배지 표에서 FIELD_MOVE_FLY에 대응하는 FLAG_BADGE06_GET)와 야외 맵 유형(Overworld_MapTypeAllowsTeleportAndFly: 도로, 마을, 도시, 바다 도로)이 필요합니다. 지도에서 마을이 MAPSECTYPE_CITY_CANFLY가 되는 것은 그 마을의 FLAG_VISITED_* 플래그가 켜져 있을 때뿐이며, 마을과 도시 16곳은 각자 전환 시 스크립트에서 자기 플래그를 켭니다. Oldale의 것은 setflag FLAG_VISITED_OLDALE_TOWN입니다.13

다른 게임들도 같은 모양입니다. FireRed의 지도는 한 페이지가 22×15칸이고 네 페이지(관동과 Sevii 제도 세 묶음)가 있으며, 각각 필드와 던전의 두 층으로 되어 있습니다. 관동의 필드 층은 38개 구역으로 90칸을 채우고, 공중날기에는 세 번째 배지가 필요합니다. FireRed의 장소는 그 FLAG_WORLD_MAP_* 플래그가 켜지면 방문한 것으로 칩니다. 각 마을의 전환 시 스크립트가 들어갈 때 그 플래그를 켜고(setworldmapflag FLAG_WORLD_MAP_CELADON_CITY), 공중날기는 방문한 칸만 받습니다.23 Crystal의 지도는 랜드마크 95개를 픽셀 위치로 배치하고 공중날기 목적지를 성도 12곳, 관동 12곳, 모두 24곳 제공합니다. 마을의 목적지는 들어갈 때 콜백으로 설정되며(VioletCityFlypointCallback: setflag ENGINE_FLYPOINT_VIOLET), 공중날기는 ENGINE_STORMBADGE를 확인합니다.24 Red의 타운맵은 4비트 격자 위에 야외 항목 37개(그중 하나는 미사용으로 표시)와 자체 위치를 가진 실내 항목 60개를 나열합니다. 도시 맵 11개 중 어디든 들어가면 wTownVisitedFlag의 그 도시 비트가 켜지는데, 소스 주석은 “mark town as visited (for flying)”(마을을 방문한 것으로 표시, 공중날기용)입니다. 공중날기 목록은 방문하지 않은 마을을 건너뛰고, 공중날기에는 오렌지배지와 야외 맵이 필요합니다.22

네 게임 중 어느 것도 처음부터 들고 다닐 지도를 주지 않습니다. 모두 플레이 도중에 건넵니다. Red와 FireRed의 타운맵은 Pallet에 사는 라이벌의 누나가 주는 도구입니다(Red에서는 플레이어가 포켓몬 도감을 받은 뒤에 내밉니다). Crystal의 맵카드는 집 다음 첫 마을인 Cherrygrove에서 받는 선물이고, Emerald의 포켓내비는 집에서 세 번째 마을인 Rustboro의 Devon 건물에서 받습니다.442345127 벽 지도는 같은 화면을 더 일찍 엽니다. Emerald는 플레이어 집 2층과 모든 포켓몬센터 1층에 걸어 두고, FireRed는 포켓몬센터, Viridian의 학교, 몇몇 집에 걸어 둡니다. Red의 HOUSE 타일셋은 Pallet에 있는 라이벌의 집에 쓰이며 벽 지도 타일을 가지고 있습니다.122344

종합하면, 이 규칙은 네 게임과 세 세대에 걸쳐 일관됩니다. 플레이어가 지도를 손에 넣으면, 지도는 방문 여부와 관계없이 지방의 모든 장소를 그립니다. 예외는 스토리나 이벤트로 가려 둔 후반 장소입니다. FireRed의 Sevii 제도 페이지는 One Island의 포켓몬센터에서 스크립트가 플래그를 켤 때까지 가려지고, 그 페이지 안에서도 Navel Rock과 Birth Island는 플레이어가 가 보기 전까지 덧칠되어 있습니다. Emerald의 Battle Frontier와 Southern Island는 랜드마크 플래그가 켜질 때까지, Crystal의 관동 지도는 플레이어가 관동에 설 때까지입니다.44451223 빠른 이동 목록에는 걸어서 들어가 본 장소만 오릅니다. 들어갈 때 켜지는 플래그로 기록되고, 야외에서만, 그리고 중반의 배지 이후에만 쓸 수 있습니다. Red와 FireRed는 세 번째, Emerald는 여섯 번째 배지입니다.13232422

4. 다른 모델: 스타듀 밸리, 동물의 숲, 꿈꾸는 섬

포켓몬은 마을과 마을 사이의 땅에 대한 하나의 답입니다. 다른 세 게임은 다르게 답하며, 그 차이 하나하나가 Kiradex가 내려야 할 선택입니다. 이 절의 수치는 각 게임의 커뮤니티 위키에서, 꿈꾸는 섬은 디스어셈블리에서 가져왔습니다. 주석에 그렇다고 적은 곳을 빼면 게임 코드와 대조하지 않았습니다.29

스타듀 밸리: 달력이 여는 허브와 바큇살

스타듀는 모든 가장자리에서 페이드합니다. 위키의 말로는 “When you reach the edge of an area or enter a building, and the screen fades to black during the transition, you’re moving between maps.”(구역의 가장자리에 이르거나 건물에 들어갈 때 전환 중에 화면이 검게 페이드하면, 맵 사이를 이동하고 있는 것이다)입니다. 워프는 맵 속성이며, 위키는 그 값을 Warp [ <int fromX> <int fromY> <string toArea> <int toX> <int toY> ]+로 제시하고 예로 “6 20 Mountain 76 9”를 듭니다.46

계곡은 허브 하나를 둘러싼 작은 그래프입니다. 펠리칸 타운은 북서쪽으로 버스 정류장과 농장에, 남서쪽으로 신더샙 숲에, 남쪽으로 해변에, 북쪽으로 산에 이어집니다.47 버스 정류장은 “connects the Farm to the west with Pelican Town to the east”(서쪽의 농장과 동쪽의 펠리칸 타운을 잇는) 곳이고, 서쪽 길을 따라 숲 뒤편의 아래쪽으로 나갈 수 있습니다.48 신더샙 숲은 “has exits to the north into the Farm, to the east into Pelican Town, to the south into The Sewers, and to the northwest into the Secret Woods.”(북쪽으로 농장, 동쪽으로 펠리칸 타운, 남쪽으로 하수도, 북서쪽으로 비밀의 숲으로 나가는 출구가 있다)입니다.49 숲 뒤편은 “consists of two disconnected sections”(서로 이어지지 않은 두 구획으로 이루어진다)인데, 농장과 산을 잇는 위쪽 길과 버스 정류장 길에서 들어가는 아래쪽 구획입니다.50 이 페이지들의 장소 목록 상자에는 숲 뒤편부터 마녀의 늪까지, 제가 세어 보니 26곳이 있습니다.51

바큇살은 날짜와 행동으로 열립니다. 산은 처음에 “only two exits: to the south leading to Pelican Town, and to the west leading to the Backwoods”(출구가 둘뿐: 남쪽은 펠리칸 타운, 서쪽은 숲 뒤편)로 시작합니다. 광산은 봄 5일에 열리고, 철도는 여름 3일의 지진 뒤에, 채석장 다리는 공예실 꾸러미나 25,000g으로 열립니다.52 사막에는 버스 수리가 필요하고, 그것은 금고 꾸러미나 40,000g이 듭니다. 비밀의 숲은 강철 도끼 이상으로 치워야 하는 통나무가 막고 있습니다. 해변의 조수 웅덩이에는 나무 300개짜리 다리가 필요합니다.53 위키는 플레이어의 기본 속도를 걷기 2, 달리기 5, 말 타기 6.6으로 적지만 단위는 없고, 저는 게임 코드를 열어 확인하지 않았습니다.54

제 해석은 이렇습니다. 포켓몬은 플레이어가 지니고 다니는 능력, 즉 배지나 비전머신으로 구역에 관문을 둡니다. 스타듀는 공동체가 해낸 일, 즉 꾸러미, 다리, 또는 정해진 날의 지진으로 관문을 둡니다. 후자는 함께 쓰는 수집 마을이 누구에게도 레벨 때문에 밀려났다는 느낌을 주지 않고 쓸 수 있는 종류입니다.

동물의 숲: 에이커 격자와 기차

게임큐브판 동물의 숲(Animal Crossing)은 마을을 에이커로 짓습니다. “Acres are grid elements measuring 16x16 spaces”(에이커는 16×16칸의 격자 요소)이고, 마을은 “five acres across by six down”(가로 5에이커, 세로 6에이커)이며, 기차역은 “always located in Acre A-3”(항상 에이커 A-3에 있다)입니다. 지도는 열에 1~5, 행에 A~F의 라벨을 붙입니다.55 전체로는 80×96칸입니다.17 이후 작품들은 격자를 바꾸었습니다. 놀러오세요 동물의 숲은 4×4에이커, 타운으로 놀러가요 동물의 숲은 5×5, 튀어나와요 동물의 숲은 5×4, 모여봐요 동물의 숲은 7×6, 42에이커입니다.55

에이커는 출현 규칙이기도 합니다. “Every time the player moves into an acre (with the exception of a player exiting their house upon loading the game), one fish and one bug spawn at the locations programmed within the acre data,”(플레이어가 에이커에 들어갈 때마다, 게임을 불러오며 집에서 나오는 경우를 빼고, 에이커 데이터에 정해진 위치에 물고기 한 마리와 곤충 한 마리가 나타난다) 그리고 플레이어가 그 에이커에서 여섯 칸 떨어지면 사라집니다.55 마을 지도는 일찍, 아르바이트 중에 너굴에게서 받습니다. 지도는 “is organized in a grid, with each square representing an acre,”(격자로 짜여 있고 각 칸이 에이커 하나를 나타낸다) 바다, 강, 건물, 집을 보여 주지만 나무, 아이템, 주민은 보여 주지 않습니다.56

기차는 게임큐브판에서 다른 마을로 가는 유일한 수단이며, 메모리 카드를 통해 갑니다. “The train ride takes a few minutes”(기차 여행은 몇 분이 걸린다). 역은 “is located at the top of the player’s town,”(플레이어 마을의 맨 위에 있다) 그리고 새 게임은 플레이어가 그곳에 도착하는 데서 시작합니다.57

제 해석은 이렇습니다. 에이커는 마을을 읽기 쉽게, 이름 붙은 칸들의 지도로 만들고, 걸음마다 주사위를 굴리지 않고도 돌아다니는 것에 보상하는 출현 규칙을 줍니다. 기차는 세계와 세계 사이의 이동을 이음매가 아니라 하나의 장면으로 만듭니다.

꿈꾸는 섬: 화면 단위로 자른 세계

젤다의 전설 꿈꾸는 섬 DX(Link’s Awakening DX)는 포켓몬의 연속 스크롤과 반대되는 방식을 택합니다. zladx 디스어셈블리 문서에 따르면 플레이는 “takes place in non-scrollable screen-wide rooms,”(스크롤되지 않는 화면 크기의 방에서 이루어진다)이고, “On the Overworld, rooms are stored as they are laid out during the game, on a 16x16 grid of rooms.”(필드에서 방들은 게임 중 배치된 그대로, 16×16 방 격자로 저장된다)입니다.58 필드 지도는 2바이트 방 포인터로 된 512바이트, 방 256개이고, 방의 타일 오버레이는 “a straight forward array of 10x8 tile numbers”(10×8 타일 번호의 단순한 배열)입니다.59 “Overworld rooms are grouped in 2x2 sections (i.e. 4 rooms). Each section has a tileset ID,”(필드의 방은 2×2 구획, 즉 방 4개로 묶이고 구획마다 타일셋 ID가 있다) 그리고 구획의 타일 32개는 그것이 필요한 방으로 넘어가는 전환 중에 교체됩니다.58 필드의 모든 방은 256바이트 wOverworldRoomStatus에 상태 바이트를 가지며, 문, 변화, 부엉이 비트와 나란히 OW_ROOM_STATUS_VISITED EQU $80이 있습니다. 이 비트는 디스어셈블리의 상수에서 읽은 것이고, 지도 화면이 그 비트를 가진 방만 그리는지는 추적하지 않았습니다.25

제 해석은 이렇습니다. 포켓몬은 연속된 세계를 스크롤하며 구역별로 이름을 붙이고, 꿈꾸는 섬은 세계를 같은 크기의 화면으로 잘라 어느 화면을 봤는지 기록합니다. 기기마다 시야가 다른 휴대폰, 세로 방향 iPhone 18 Pro Max에서 가로 10.3타일, 펼친 iPhone Duo에서 29.7타일인 화면에서는, 모든 방에 레터박스를 두지 않고 통하는 것이 스크롤 모델뿐입니다. 브리프가 그것을 쓰는 이유입니다.60

5. 기법을, 숫자가 붙은 규칙으로

측정이 뒷받침하는 규칙을 각각의 출처와 함께 적습니다. 규칙이 측정된 사실을 권고로 바꾸는 곳에서 그 권고는 제 것이며, 규칙의 동사가 그 점을 드러냅니다.

요소 규칙 출처
속도 걷기 한 셀은 16프레임, 약 0.27초. Kiradex의 한 타일은 0.25초. 모든 이동을 그 게임 자신의 걷기 기준 초로 잴 것. Red, Crystal, Emerald의 스텝 코드, GBATEK, PlazaRig.swift
도로 길이 이동 축을 따라 화면 2~10장. 게임의 첫 도로는 2~6장. 측정한 도로 16개
굽이 가로지르는 더 긴 쪽 걸음은 도로 긴 변의 1.15~1.70배, 돌아오는 길은 0.95~1.42배. 도로 크기는 경계 상자가 아니라 경로로 정할 것. 양 끝이 걸어서 이어지는 도로 아홉 개에서 최단 걸음을 긴 변으로 나눈 값
첫 구간 문에서 다음 마을의 주요 문까지 15~25초. 1분짜리 구간은 길이 아니라 던전. Emerald 58셀, FireRed 94셀. 숲이나 동굴을 지나는 250, 267, 314셀
비율 면적으로 길은 마을의 2~4배. 지도 화면에서는 5.9 대 1, 마을은 한두 칸이므로. Crystal 1.97, Red 2.65, Emerald 3.70, FireRed 3.87, Emerald의 지도
밀도 인카운터 땅은 첫 도로 맵의 14%~23%이고, 세 번째와 네 번째 도로에서는 4%~9%로 줄어든다. 걸을 수 있는 땅 기준으로 첫 도로는 19%~38%. 첫 도로에는 트레이너를 두지 않는다. 도로 표, 걸을 수 있는 셀 대비 풀
리듬 인카운터 땅에서는 대략 아홉 걸음에 한 번 눈여겨볼 것을. 도착 직후 몇 걸음은 유예를 둔다. 하한과 오르막으로 가뭄과 홍수를 짧게 유지할 것. Emerald의 네 걸음 면제, 그 뒤 rate 20, 보정 없이 11.1%. FireRed의 쿨다운과 가산치
돌아오는 길 가는 길보다 짧고, 턱이 있으며 양 끝이 걸어서 이어지는 도로 아홉 개 모두에서 2%~44% 짧다. 돌아오는 길의 풀 셀은 0~5로, 가는 길의 4~19와 대조된다. 턱은 돌아오기 위한 일방통행 지름길이지 결코 앞길을 막는 벽이 아니다. 도로 아홉 개, 풀 최소화 탐색
이음매 두 구역이 열린 이음매로 만나게 하는 것은 양쪽이 같은 바닥 세트로 가장자리를 그리는 곳에서만. 그림이 바뀌는 곳에는 문이 둘인 건물을 둘 것. Red 78개 중 76개, Crystal 142개 중 138개, 기본 세트가 다른 3세대 연결은 134개 중 0개와 120개 중 0개, 서로 다른 두 장소를 잇는 Red의 모든 게이트
이웃 띠 이웃 구역을 가장자리 너머로 적어도 시야의 절반만큼 그릴 것. 15셀 화면에 대한 3세대의 7셀(동쪽은 8셀), 10셀에 대한 1세대의 6셀
연결 오프셋은 정상이다. 모든 연결은 오프셋을 뒤집은 역방향을 가지며, 한쪽만 있는 연결은 의도된 그리기 요령이다. Emerald 134개 중 36개에 오프셋, 134개 중 134개가 상호적. FireRed의 Saffron
지명 카드 들어갈 때 약 3초 동안 장소 이름을 보여 줄 것. Emerald의 지명 표시, 약 190프레임
게이트 게이트는 규칙과 보상이 머무는 곳이다. 이정표 확인, 경비원, 수에 이르면 주는 선물. Red의 배지 확인, 목마른 경비원, 잡은 10종, 30종, 50종에 주는 선물
지도 화면 이름 붙은 직사각형의 성긴 격자. 대부분의 장소는 한 칸, 가장 큰 것도 몇 칸. Emerald 28×15, 직사각형 95개 중 49개가 한 칸, 가장 큰 것은 4×3. 동물의 숲의 5×6에이커
빠른 이동 플레이어가 지도를 가지면 방문 여부와 관계없이 모든 장소를 보여 주되, 스토리나 이벤트 플래그로 가려 둔 몇 곳은 예외. 빠른 이동은 가 본 곳만 보여 주며, 그것은 들어갈 때의 플래그로 정해지고, 야외에서만 쓸 수 있다. 타운맵, 맵카드, 포켓내비, 벽 지도. Red의 wTownVisitedFlag, Crystal의 공중날기 목적지, Emerald의 FLAG_VISITED_*, FireRed의 FLAG_WORLD_MAP_*. 지도 화면과의 관계까지 추적하지 않은 방문 기록으로 꿈꾸는 섬의 OW_ROOM_STATUS_VISITED 비트
개방 구역은 능력뿐 아니라 행동과 날짜로도 열린다. 스타듀의 광산, 철도, 채석장, 사막, 비밀의 숲. 풀베기로 267셀이 156셀로
전환 하나의 야외 세계 안에서는 이음매로, 문과 세계의 끝에서는 페이드로. 포켓몬의 이음매, 스타듀의 페이드, 꿈꾸는 섬의 화면 밀기
방향 도로는 기기의 긴 축을 따라 놓을 것. 한 시야에 통째로 들어오는 도로에는 더 드러낼 것이 남아 있지 않다. 10월 3일의 타일 수. Emerald Route 101의 20×20 대 펼친 Duo의 29.7×20.9

표의 출처: 1절의 스텝 코드와 프레임 타이밍,12315 Kiradex의 걷기 속도,4 도로, 이동, 풀, 연결 스크립트,567188 인카운터 코드,3132 Emerald의 버퍼, 경계 넘기, 지명 표시 코드,91021 게이트 스크립트,1920 지도 화면과 플레이어가 그것을 얻는 방법, 그리고 공중날기,1112132345244422 스타듀 밸리, 동물의 숲, 꿈꾸는 섬,465253555825 이 시리즈 첫 글의 기기별 타일 수.60

이 가운데 세 규칙은 한마디씩 더 할 만합니다.

이음매 규칙은 엔진이 아니라 그림에 관한 규칙으로 적었습니다. 게임보이는 이웃의 띠를 현재 맵의 블록셋으로 그렸기 때문에, 다른 타일셋의 이웃은 아예 보여 줄 수 없었습니다. 게임보이 어드밴스는 넘어갈 때까지 현재 맵의 타일셋으로 띠를 그리며, 제 해석으로는 그것이 이음매를 하나의 기본 세트에, 그리고 대부분 기본 메타타일에 묶어 둔 이유입니다.38108 저는 둘 다 타일 메모리의 한계로 읽으며, 아틀라스 하나를 그리는 휴대폰에는 그런 한계가 없습니다. 남는 것은 시각적인 이유입니다. 화면을 가로지르는 직선에서 재질이 바뀌는 길은, 엔진이 그것을 필요로 했든 아니든 이음매로 보입니다. 그래서 이 규칙은 아무것도 강제하지 않을 때에도 앞부분(바닥이 이어지는 곳에서는 열린 채로 만난다)과 뒷부분(그림이 바뀌는 곳에는 건물을)을 그대로 둡니다.

빠른 이동 규칙은 그대로 옮겨 올 가치가 가장 큰 규칙입니다. 여기서 측정한 포켓몬 게임은 모두 플레이 초반에 지도를 건네고, 방문 여부와 관계없이 모든 장소를 그리며(스토리나 이벤트 플래그로 가려 둔 몇몇 후반 장소는 예외), 지름길에만 관문을 둡니다. 그리고 모두 지름길을 돈을 내서가 아니라 어딘가로 걸어가 봄으로써 얻게 합니다.44451213232224 XP가 현실에서 스캔한 카드로만 나오는 수집 앱에서는 방문 플래그가 올바른 화폐입니다. 드는 것은 걸음뿐이기 때문입니다.27

방향 규칙은 정전이 아니라 휴대폰에서 나옵니다. 세로 방향 Pro Max는 Kiradex의 배율로 10.3×22.4타일을, 펼친 iPhone Duo는 29.7×20.9타일을 보여 줍니다. 그래서 남북으로 뻗은 도로는 흔한 휴대폰에서 그 길이의 22타일을 한 번에 보여 주고, 카메라가 가운데에 두는 수집가의 앞쪽으로 약 11타일입니다. 동서로 뻗은 도로는 펼친 Duo에서만 30타일을 한 번에 보여 주고, 앞쪽으로 약 15타일입니다.602717 20×20인 Emerald Route 101은 펼친 Duo의 한 시야에 통째로 들어오므로, 그만큼 짧은 도로는 거기서 더 드러낼 것이 없다는 뜻입니다.617

6. Apple의 방식: 시야, 이음매, 룸, 그리고 지도

Kiradex World 아래의 엔진은 첫 글이 제시한 것입니다. 2D 렌더러로 쓰는 RealityKit 장면, 텍셀당 정수 개의 기기 픽셀로 맞춘 직교 카메라, 한 번의 그리기 호출로 그리는 MeshDescriptor 메시 하나로서의 바닥, 불투명도 임계값을 가진 UnlitMaterial 재질, 그리고 꺼 둔 RealityView의 모션 블러와 톤 매핑입니다.60 건물 글은 여기에 두 번째 메시에서 깊이 순으로 정렬한 오브젝트, 데이터로서의 워프, 그리고 스테이지에 새 정체성 .id(floor.name)을 주어 층을 제자리에서 바꾸는 방식을 더했습니다. 이렇게 하면 SwiftUI가 RealityView 하나를 허물고 다음 것을 짓습니다.37 울타리 너머의 구역에는 이 엔진에서 세 가지가 더 필요합니다. 이음매 너머 이웃 구역의 모습, 끊김 없이 서버에서 룸을 바꾸는 방법, 그리고 지도 화면입니다. 그중 어느 것도 아직 만들지 않았고, 이 절의 어떤 내용도 휴대폰에서 측정하지 않았습니다. 이것은 브리프가 딛고 선 계획이며, 비용은 하나하나 이름을 붙이고 측정하지 않았다고 표시했습니다.

휴대폰에 보이는 것

타일 수는 첫 글의 표에서 가져왔습니다. Apple의 사양 페이지와 Xcode 27 시뮬레이터 프로필로부터 Kiradex의 정수 배율에서 계산한 값입니다.60

기기와 방향 텍셀당 픽셀 보이는 타일(가로×세로) 시야의 절반
iPhone 18 Pro Max, 세로 8 10.3×22.4 가로 6, 세로 12
iPhone Duo 바깥 디스플레이, 세로 6 14.6×21.2 가로 8, 세로 11
iPhone Duo 안쪽 디스플레이, 펼침 6 29.7×20.9 가로 15, 세로 11

마지막 열은 시야의 절반을 올림한 값으로, 이음매 규칙이 요구하는 이웃 띠입니다.17 Apple은 iPhone Duo의 안쪽 디스플레이를 1878×2670픽셀, 인치당 430픽셀로, 바깥 디스플레이를 1398×2034픽셀, 인치당 460픽셀로 제시합니다.61 안쪽 디스플레이의 타일 수는 이 패널 픽셀에서 나온 것이 아닙니다. 시뮬레이터의 논리 프레임버퍼 2007×2853, 배율 3.0에서 나왔습니다(2853 ÷ 96은 29.7, 2007 ÷ 96은 20.9). 첫 글이 설명하듯 이 버퍼는 유리에 맞춰 약 0.936배로 다운샘플링되므로, 실기기에서도 같은 수의 타일이 패널을 채워야 합니다. 텍셀당 약 5.6 패널 픽셀이며, 컴포지터가 첫 글의 예상대로 다운샘플링한다면 그렇습니다. 이는 실기기에서 검증되지 않았고, 첫 글의 첫 단계는 기기에서 nativeScale을 로그로 남기는 것입니다.6017 휴먼 인터페이스 가이드라인은 게임이 “look good and behave well at various aspect ratios”(다양한 화면비에서 보기 좋고 잘 작동하도록) 하라고 요구하며, 첫 글은 이를 레터박스 대신 더 많은 세계를 보여 주라는 근거로 읽었습니다. 광장이 하는 일이 바로 그것입니다.6260

구역에 대해서는 두 가지가 따라 나옵니다. 카메라가 수집가를 따라가면 앞쪽 시야는 시야의 약 절반입니다.27 남북으로 뻗은 도로는 어느 휴대폰에서나 잘 보이는 도로입니다. 세로 방향 Pro Max에서는 한 번에 22타일, 앞쪽으로 약 11타일을 보여 주고, 펼친 Duo에서는 한 번에 21타일, 앞쪽으로 약 10타일을 보여 줍니다. 동서로 뻗은 도로는 펼친 Duo에서는 한 번에 30타일, 앞쪽으로 약 15타일을 보여 주지만 세로 방향 Pro Max에서는 10타일, 앞쪽으로 약 5타일뿐이어서, 목적지가 가까운 곳에 어울립니다.6017 그래서 브리프의 긴 산책길인 초원 산책로는 남북으로 뻗고, 동서로 가장 길게 뻗은 구역인 바인더 거리(44×14, 너비가 높이의 세 배 이상)는 펼친 Duo에서라면 어디에 서 있든 대부분이 보이는 가게 앞 거리가 됩니다. 호숫가(36×20)와 갤러리 지구(30×20)도 가로로 넓지만, 브리프에서 이들은 어딘가로 가는 길이 아니라 머무는 곳, 즉 물가와 미술관 지구입니다.2617

RealityKit에서의 이음매

건물 글의 층 교체는 이음매에 맞지 않는 도구입니다. RealityView 하나를 허물고 다음 것을 지으려면 그것을 가릴 페이드가 필요한데, 앱의 문에는 아직 페이드가 없습니다. 지금은 문 위로 한 걸음 내디딘 지 220밀리초 뒤에 장소가 바뀌고, 층 변경은 페이드 없이 스테이지를 바꾸며, 이 시리즈의 모션 글이 그 둘을 모두 덮을 베일을 제안합니다. 이음매에는 정의상 페이드가 없습니다.376316 그래서 이음매 계획은 장면을 하나로 유지합니다. 수집가가 연결이 있는 가장자리에서 시야의 절반 이내로 다가오면, 스테이지는 이웃 구역의 바닥을 첫 번째와 같은 종류의 MeshDescriptor로 두 번째 메시로 짓고, 월드 단위로 연결의 오프셋 위치에 놓으며, 이웃의 오브젝트를 각자의 깊이에 더합니다. 수집가의 발이 가장자리를 넘으면 스테이지는 기준을 옮깁니다. 이웃이 현재 구역이 되고, 옛 구역은 뒤쪽 띠가 되며, 지금은 맵 범위 안에 묶여 플레이어를 따라가는 카메라는 둘 다 불러와져 있는 동안 그 합집합 범위 안에 묶입니다.2726

서류상으로 이것을 싸게 만드는 엔진의 사실이 세 가지 있습니다. 바닥은 구역마다 메시 하나와 그리기 호출 하나이므로, 이웃 구역이 더하는 것은 바닥의 그리기 호출 하나와 오브젝트의 호출 하나입니다.6037 모든 픽셀은 잘라 내기 방식이고 깊이를 쓰므로, 이웃의 나무는 현재 구역과 같은 깊이 규칙으로 수집가와 앞뒤가 정해지며 새 정렬이 필요 없습니다.37 그리고 포지는 이미 구역 전체를 글자, 오토타일된 바닥, 오브젝트, 워프로 내보내므로, 이웃 구역은 같은 종류의 두 번째 파일입니다. 브리프는 여기에 connections 목록을 더합니다.1426 이 중 어느 것도 알려 주지 않는 것은, 두 번째 메시를 필요한 순간에 짓는 비용과, 그것을 한 프레임 안에 지을 때 끊김이 생기는지입니다. 이는 측정하지 않았습니다. 그래서 브리프의 검사 6은 두 부분으로 되어 있고, 둘 다 이웃 메시를 짓기 전부터 경계 넘기가 끝날 때까지 접근 전체를 다룹니다. 메인 스레드 정체를 잡는 프레임별 타이밍 로그와, 검은 프레임을 잡는 캡처된 모든 프레임의 검사입니다. 표본 검사로는 부족합니다. 초당 60장 중 검은 프레임 한 장은 콜백의 타이밍을 흐트러뜨리지 않을 수 있고, 100밀리초마다 하는 표본은 60헤르츠에서 여섯 프레임 중 하나만 봅니다.17 타이밍 부분과 모든 프레임 규칙은, 밝기를 표본으로 확인하던 조사 자료의 검사에 제가 더한 것입니다.

오토타일은 GBA의 규칙이 다루지 않는 유일한 것입니다. 3세대가 이음매를 공유하는 바닥에 묶어 둔 것은 이웃의 띠가 현재 맵의 타일로 그려졌기 때문입니다.108 Kiradex는 모든 구역을 아틀라스 팔레트 하나로 그리므로 그 한계는 해당하지 않지만, 구역 가장자리의 블롭 오토타일은 그 구역 자신의 글자로 계산됩니다. 포지가 이음매 너머를 보지 않으면, 이음매를 넘는 길은 양쪽에서 테두리로 끝나 버립니다. 그래서 브리프는 포지가 모든 연결에 걸쳐 가장자리 마스크를 계산하게 합니다.26

룸, 접속 상태, 재연결

Kiradex의 광장은 서버의 룸입니다. 최대 약 40명이 들어가는 룸을 지역별로 샤딩하며, FastAPI와 WebSockets 위에서 돌아갑니다.27 울타리 너머의 구역은 자연스럽게 또 하나의 룸이 되고, 여기서 싱글 플레이어 휴대용 게임기는 겪은 적이 없는 문제가 생깁니다. 이음매 건너편의 사람들입니다. 계획은 이렇습니다. 클라이언트는 이웃 룸의 띠를 그리기 시작할 때 그 룸에서 걷는 사람들을 구독해서, 중앙 광장 가장자리에서 바인더 거리의 사람들이 보이게 하고, 경계를 넘는 순간 자기 룸을 바꾸어 걷는 사람이 멈추지 않게 합니다.26 문과 트램에는 페이드, 즉 모션 글의 브리프가 문에 더하는 베일을 쓰고, 그 페이드가 재연결을 덮습니다. 건물 조사 자료가 실내에 대해 이미 제안한 그대로입니다.1626 검은 화면에 대한 첫 글의 해법이 이 페이드에 적용됩니다. RealityView를 담은 SwiftUI 뷰의 불투명도를 애니메이션하면 그려지지 않은 채로 남았으므로, 페이드는 그 위에 그리는 베일로 합니다.60

서버에는 클라이언트가 그리는 것과 같은 지도가 필요합니다. 지금 server/app/plaza.json은 마을의 글자를 담고 있어 서버가 걸음을 검증할 수 있습니다. 브리프에서는 각 구역의 사본이 글자와 연결을 담아, 이음매를 넘는 걸음이 이음매 양쪽에서 검증됩니다.6026 실제 네트워크에서 룸 전환에 드는 비용, 그리고 이음매 근처에서 두 번째 룸을 구독하면 광장의 메시지 양이 두 배가 되는지는 측정하지 않았습니다.

SwiftUI로 만드는 지명 카드, 지도, 트램

구역의 이름은 픽셀 레이어가 아니라 SwiftUI에 속합니다. 첫 글은 5텍셀 픽셀 폰트가 Kiradex의 배율에서 13.3포인트나 10포인트가 되고, 뒤의 것은 휴먼 인터페이스 가이드라인의 최소 11포인트에 못 미친다는 것을 확인하고, 대화 텍스트를 UI 배율의 SwiftUI로 옮겼습니다. 지명 카드도 같은 종류의 텍스트입니다.60 타이밍은 Emerald에서 가져옵니다. 화면에 약 3초입니다.21

지도 화면은 작은 모델 위의 SwiftUI 뷰입니다. 이름 붙은 직사각형의 격자, 현재 구역, 그리고 방문한 구역의 집합입니다. 펼친 Duo에서는 세계 옆에 패널로 둡니다. 월드 계획이 수집가의 프로필 카드를 광장 옆에 두는 방식과 같습니다(“The plaza on the open inner display is the best version of this: wide view, your profile card beside the world when you tap someone”, 펼친 안쪽 디스플레이의 광장이 이것의 가장 좋은 형태다: 넓은 시야, 누군가를 탭하면 세계 옆에 뜨는 프로필 카드). 휴대폰에서는 시트로 띄웁니다.27 트램은 지도에서 출발하는 워프입니다. 페이드아웃하고, 룸을 바꾸고, 목적지 정류장에서 페이드인합니다.

방문한 구역의 집합은 수집가와 함께 다녀야 합니다. 휴먼 인터페이스 가이드라인의 게임 페이지는 “Let players pick up their game on any of their devices,”(플레이어가 어느 기기에서든 게임을 이어서 할 수 있게 하라)라고 하며, 사람들이 “start back up exactly where they left off on a different device.”(다른 기기에서 멈춘 바로 그 자리부터 다시 시작할 수 있도록)라고 말합니다.62 휴대폰에서 연 트램 정류장은 iPad에서도 열려 있어야 하므로, 방문한 구역의 집합은 앱의 로컬 저장소가 아니라 서버에 있는 수집가의 프로필과 함께 둡니다.26 이는 월드 계획 3절을 넓히는 것으로, 그 절에는 “Our server holds only the public profile card and the economy”(우리 서버는 공개 프로필 카드와 경제만 보관한다)라고 적혀 있습니다. 저는 방문한 구역의 집합을 그 옆에 필드 하나로 더하고 싶습니다. 수집가가 다섯 구역 중 어디에 들어가 봤는지만 담고, 위치도 텍스트도 방문 시각도 담지 않으며, 나머지와 마찬가지로 Game Center 플레이어 ID를 키로 삼습니다. 계획이 요구하는 개인정보 검토도 이것까지 다루어야 할 것입니다.2726

비용, 그리고 측정하지 않은 것

이 절의 어떤 것도 시간을 재지 않았습니다. 측정하지 않은 비용은 다음과 같습니다. 수집가가 가장자리에 다가가는 순간 이웃 구역의 바닥과 오브젝트 메시를 짓는 일, 둘 다 불러와져 있는 동안 두 구역의 메시를 그리는 일, 이음매 근처에서 두 번째 룸을 구독하는 일, 그리고 경계를 넘을 때의 룸 전환입니다. 이것들을 어떻게 잴지는 첫 글의 캡처 규칙이 정합니다. iPhone Duo 시뮬레이터에서 RealityKit 프레임은 호스트가 아니라 테스트 번들 내부(XCUIScreen.screens[1])에서 캡처할 때만 정확합니다.60 브리프의 검사 6은 이음매 앞에서 이웃이 보이는지 확인하는 데 바로 그 캡처를 쓰고, 모든 프레임 검사와 CADisplayLink 콜백에서 읽는 프레임 타이밍 로그는 시뮬레이터가 아니라 기기 빌드에서 실행합니다. 펼친 iPhone Duo가 손에 들어오면 그것으로, 그때까지는 iPhone 18 Pro Max로 합니다. 이 글을 쓰는 지금 제 Mac에 페어링된 iPhone Duo가 없기 때문입니다.64 표시된 모든 프레임을 기록한다고 입증된 캡처 방법은 아직 없습니다. 녹화의 프레임 수와 타이밍 로그의 콜백 수를 맞대는 검사의 프레임 수 일치가, 어떤 방법이 그것을 해내는지를 가립니다.

7. 브리프: Kiradex가 만들 것과 통과해야 할 검사

저자의 종합. 아래는 제 제안입니다. 1절부터 6절을 바탕으로, Kiradex 저장소에 있는 월드 계획, 그중 4절(“The game”)과 7절(“Order of work”)에 맞추어 짰습니다.2726 어떤 포켓몬 게임의 장소, 생물, 표식의 이름도 쓰지 않습니다. 메커니즘을 빌리는 곳에서는 원래 게임의 용어가 아니라 5절의 규칙을 인용합니다. 크기는 모두 16픽셀 타일 단위이고, 걸음의 길이는 앱 자체의 경로 탐색에서의 비용이며, 대각선 한 걸음은 √2타일로 셉니다(항목 3).28 시간은 모두 그 길이를 명목상 초당 4타일로 걸은 값으로, 정전과 비교하기 위한 수치이지 측정한 수치가 아닙니다. 모션 글의 브리프라면 60헤르츠에서 곧은 한 타일을 16틱, 초당 3.75타일로 걷고 대각선은 23틱으로 올림하는데, 그 경우 여기의 시간은 모두 곧은 걸음에서는 15분의 1, 대각선에서는 약 12분의 1 늘어납니다.41617

Kiradex의 루프는 현실 세계에 있습니다. XP는 스캔해서 등록한 카드로만 나옵니다. “XP comes only from the real world, which is the point of the app.”(XP는 현실 세계에서만 나온다. 그것이 이 앱의 핵심이다).27 따라서 걷기는 콘텐츠가 아니라 비용이며, 모든 구역은 걷는 사람에게 자기 컬렉션으로 할 일을 주어야 합니다. 보여 주기, 그것을 두고 교환하기, 그것으로 코스메틱 얻기, 아니면 스캐너로 돌아가라는 안내를 받기. 걸어서 찾거나 얻은 것은 결코 카드나 XP가 되지 않으며, 세계 안의 어떤 것도 월드 계획이 이미 정한 상점을 거치지 않고는 돈으로 팔리지 않습니다.27

1. 다섯 구역: 중앙 광장과 그 너머 넷

구역 어떤 곳인가 크기(타일) 연결 수집 루프에서의 역할
중앙 광장(기존) 마을: 집, 홀, 키오스크, 분수 테라스, 도착 마당 40×30 허브 도착하고, 가장 아끼는 카드를 자랑하고, 방과 홀에 들어간다
바인더 거리 상점가: 건물 키트의 카드 가게, 교환소, 원하는 카드 게시판, 나중에 시장 노점 여섯 개가 줄지은 곳 44×14 중앙 광장 동쪽, 열린 이음매 코인을 코스메틱에 쓴다. 마을 수집가들이 보여 달라고 하는 것을 본다. 교환 화면. 그 단계가 오면 마켓플레이스 노점
초원 산책로 초원과 작은 숲을 지나는 공원길. 발견물이 나타나는 꽃밭과, 호수 쪽에서만 열리는 문이 달린 생울타리 귀갓길 24×60, 긴 축은 남북 중앙 광장 북쪽, 열린 이음매 발견물(항목 6), 친구와의 산책, 호수로 가는 길
호숫가 산책로의 끝: 물가, 잔교, 벤치, 보트 하우스 36×20 초원 산책로 북쪽, 열린 이음매 해 질 녘 앉아서 카드를 보여 주는 조용한 곳. 주간 모임 장소
갤러리 지구 돌로 된 지구: 미술관과 수집가들의 전시 갤러리 30×20, 그리고 8×6 아치 건물 중앙 광장 서쪽, 아치를 거쳐(문 두 개) 서버 전체에서 완성된 세트가 미술관을 채운다. 아치에 있는 이정표 관리인(항목 7)

중앙 광장 너머의 총면적은 616 + 1,440 + 720 + 600, 3,376타일로 중앙 광장 1,200의 2.8배이며, 정전의 범위 1.97~3.87 안에 듭니다(5절, 비율).1733 갤러리 지구가 건물 뒤에 있는 것은 다른 바닥 세트의 돌로 그리기 때문입니다(5절, 이음매). 나머지 셋은 중앙 광장의 잔디와 포장을 함께 쓰므로 열린 이음매로 만나며, 모두 세 곳입니다. 중앙 광장 동쪽 가장자리에 바인더 거리, 북쪽 가장자리에 초원 산책로, 그리고 초원 산책로 북쪽 가장자리에 호숫가입니다.26 바인더 거리의 원하는 카드 게시판은 마을 수집가들이 보여 달라고 하는 것을, 이미 그 판정을 하는 코드(Kiradex/World/Wants.swift)로 실제 카드와 대조해 보여 줍니다. 노점은 마켓플레이스를 기다리며, 월드 계획은 마켓플레이스를 이후 단계에서 eBay를 통해 운영합니다.6527

칸 하나가 10타일인 16×12 지도 화면에 그린 브리프의 다섯 구역 모식도. 맨 위에 호숫가, 그 아래 초원 산책로, 아래 가운데 중앙 광장, 중앙 광장의 동쪽에 바인더 거리, 서쪽에 점선 아치를 사이에 두고 갤러리 지구. 점은 각 구역의 트램 정류장이며, 메모에 중앙 광장 너머 3,376타일, 중앙 광장 1,200의 2.8배라고 적혀 있다.

제안한 구역을 지도 화면의 격자에 맞추어 그린 것. 모식도일 뿐입니다. figures/make_figures.py가 그렸으며, 이 스크립트는 각 직사각형이 그 구역의 크기를 10으로 나누어 반올림한 값인지 확인합니다.

검사: 4(비율)와 5(방향).

2. 거리와 시간

이동 목표(타일) 초당 4타일 기준 정전 참고
도착 마당에서 카드 가게 문까지 최대 60 최대 15초 5절, 첫 구간: 15~25초
도착 마당에서 호숫가 잔교까지, 가는 길 110~120 28~30초 첫 구간(15~25초)보다 길고, 최대 40초인 정전의 길 구간과 1분짜리 던전보다는 짧다. 굽이, 가는 길은 긴 변의 1.15~1.70배
호숫가 잔교에서 도착 마당까지, 돌아오는 길, 생울타리 문 경유 가는 길의 0.8배 이하 최대 24초 돌아오는 길은 더 짧다
도착 마당에서 아치를 지나 미술관 문까지 최대 70 최대 18초 첫 구간
어느 구역에서든 방문한 어느 구역으로든 트램으로 페이드 한 번 약 1초와 재연결 빠른 이동, 전환

초원 산책로의 60타일 길이는 굽이져 78~90타일의 경로가 되며, 계수는 1.3~1.5입니다(5절, 굽이).26 길만으로는 돌아오는 길을 짧게 만들 수 없습니다. 모든 걸음을 양방향으로 걸을 수 있는 격자에서는 도착 지점에서 잔교까지의 최단 걸음이 곧 돌아오는 최단 걸음이고, 더 곧은 길이 있다면 가는 길에도 그 길을 쓰기 때문입니다. 단축에는 한쪽으로만 통하는 무언가가 필요합니다. 여기서는 그것이 생울타리 문입니다. 폭 2타일의 생울타리 오솔길이 초원 산책로의 동쪽을 따라 잔교와 일직선으로 곧게 내려와, 중앙 광장 북쪽 가장자리의 홀과 그 동쪽 집 사이로 나옵니다. 거기서 두 건물 사이의 잔디가 도착 마당 쪽으로 내려갑니다. 오솔길의 호수 쪽 끝에 있는 문은 호수 쪽에서만 열립니다. 갈 때는 닫혀 있어 길이 굽이지고, 돌아올 때는 열려 오솔길이 곧습니다. 이것이 정전의 일방통행 귀갓길 지름길(5절, 돌아오는 길)을 평평하게 눕힌 것입니다. 세 구역을 항목 3의 공유 8방향 그래프로 모델링했고, 마을은 포지가 지금 그리는 그대로, 오솔길과 잔교는 앞에서 말한 대로 배치했습니다. 저는 초원을 가로지르는 생울타리 네 줄, 12행마다 한 줄, 각각 폭 2타일의 틈을 둔 것으로 길을 굽이지게 하기로 했습니다. 대각선 걸음은 모든 굽잇길을 짧게 질러갑니다. 어느 틈 위치에서든, 같은 간격의 생울타리 두 줄로는 이 그래프에서 초원을 78타일 굽이지게 할 수 없습니다. 가장자리에서 가장자리까지 최대 66.46타일에 그칩니다. 같은 간격의 세 줄이면 가능하지만 아슬아슬합니다. 8,000가지 틈 위치 중 6가지가 78~79.77타일의 굽이를 만들고, 그 6가지 중 5가지는 가는 길도 110~120타일 범위 안의 114.05~119.02타일이며, 돌아오는 길은 가는 길의 0.740~0.772로 0.8 목표 아래입니다. 네 줄이면 160,000가지 위치 중 5,912가지에서 78~90타일의 굽이가 나오므로, 포지가 초원을 배치할 여지가 남습니다. 네 줄로 정한 이유는 이 여유이며, 그래프가 그것을 강제하는 것은 아닙니다. 그 네 줄 레이아웃에서 돌아오는 길은 88.07타일, 가는 길은 108.74~133.75타일입니다. 0.8 목표를 맞추려면 가는 길이 최소 110.09타일이어야 하고, 110~120타일의 가는 길 범위 안에서는 레이아웃 4,111개 모두가 이를 충족해 0.73~0.80입니다. 문을 양방향으로 열면 두 걸음은 같아집니다.66 이전 모델의 생울타리 두 줄로 더는 충분하지 않은 것은 8방향 걷기 때문입니다. 오솔길은 이미 곧아서 돌아오는 길은 91타일에서 88.07타일로만 줄지만, 굽이진 가는 길에서는 훨씬 많이 깎아 내므로, 초원을 더 세게 굽이지게 하지 않으면 문의 절약이 줄어듭니다. 같은 모델이 범위의 하한도 정합니다. 이 모델의 어떤 레이아웃도, 시도한 어떤 오프셋이나 잔교 위치에서도 가는 길이 107.18타일 아래로 내려가지 않고, 돌아오는 길이 88.07타일 아래로 내려가지도 않습니다. 그래서 가는 길이 110타일보다 한참 짧으면 0.8 목표를 맞추지 못합니다.66 초원의 단구에서 한쪽으로만 내려가는 턱으로도 정전의 방식으로 같은 효과를 낼 수 있지만, 건물 작업이 턱을 거부했으므로 그 턱은 높이 글로 미루고 거기서 정합니다.3626

검사: 3(거리).

3. 데이터로서의 연결

각 구역은 town.json 같은 포지 출력물입니다. 글자, 오토타일된 바닥, 오브젝트, 워프, 도착 지점에 더해 connections: [{"dir": "north"|"south"|"east"|"west", "area": "<id>", "offset": <tiles>}]를 가지며, 오프셋은 공유하는 변을 따라 잰 이웃 구역 원점의 위치로, 3세대의 관례를 따릅니다.148 모든 연결은 오프셋을 뒤집은 역방향을 가집니다(5절, 연결). 예외는 없습니다. 정전의 한쪽 연결은 그리기 요령이고, 이 브리프에는 필요 없습니다. 서버에 있는 각 구역의 사본은 글자와 연결을 담고, 걸음은 이음매를 넘어 검증됩니다.6026

보행 그래프 하나가 양쪽을 모두 섬깁니다. 앱의 TileMap.path는 8방향을 탐색하며, 대각선 걸음의 비용은 √2이고 통과하는 두 타일이 모두 걸을 수 있을 때만 허용됩니다. 그래서 아무도 벽 모서리를 깎고 지나가지 않습니다. 서버의 server/app/rooms.py에 있는 Plaza.path는 4방향을 탐색하지만, 그 주석은 스스로를 “the same walk the app takes”(앱과 같은 걸음)라고 부릅니다.28 브리프는 클라이언트의 탐색을 계약으로 삼습니다. 서버 쪽 변경은 Plaza.path를 같은 8방향, √2, 모서리 깎기 금지 탐색으로 바꾸고, 둘 다 생울타리 문(항목 2)을 방향이 있는 간선으로 읽습니다. 호수 쪽에서 곧은 걸음으로만 들어갈 수 있고, 호수 쪽으로는 절대 나갈 수 없습니다. 이 브리프의 거리는 모두 그 그래프 위에서 잽니다.

검사: 1(상호성), 2(경계 넘는 지점), 12(서버 일치).

4. 열린 이음매, 페이드 없음

열린 이음매를 넘을 때 페이드는 없습니다(5절, 전환). 클라이언트는 이웃 구역의 바닥과 오브젝트를 적어도 시야의 절반 깊이까지 그립니다. 동서로 넘는 이음매에서는 펼친 Duo의 29.7의 절반인 15타일, 남북으로 넘는 이음매에서는 세로 방향 Pro Max의 22.4의 절반인 12타일입니다(5절, 이웃 띠).6017 포지는 각 이음매에 걸쳐 오토타일 마스크를 계산하므로 이음매를 넘는 길이 테두리로 끊기지 않고, 모든 이음매에서 마을 울타리에 폭 2타일 이상의 틈을 내며, 틈의 셀은 양쪽에서 걸을 수 있게 합니다.1426 포지가 지금 마을 둘레에 12타일 깊이로 그리는 숲(MARGIN = 12)은 공유하는 변 전체에서 이웃 구역에 자리를 내줍니다. 거기서는 이웃의 띠가 숲 여백을 대신하고, 숲은 어느 구역도 붙지 않은 곳에만 남습니다. 이는 조사 자료를 고친 것입니다. 조사 자료는 2타일 틈을 숲 여백에도 내기만 했으므로, 이웃 띠 대부분이 숲에 덮인 채로 남았을 것입니다.1426 클라이언트는 이웃 룸의 띠를 그리기 시작할 때 그 룸에서 걷는 사람들을 구독하고, 경계를 넘는 순간 자기 룸을 바꿉니다.26

검사: 6(검은 프레임 없음, 메인 스레드 정체 없음, 이음매 앞에서 띠가 보일 것).

5. 지명 카드

이음매나 트램으로 구역에 들어가면 그 이름이 미끄러져 들어와 머문 뒤 약 3초 만에 사라집니다(5절, 지명 카드). UI 배율의 SwiftUI로 그리며, 픽셀 레이어에는 절대 그리지 않습니다.2160

검사: 7(지명 카드 타이밍).

6. 초원 산책로의 발견물

  • 어디에. 꽃밭은 초원 산책로의 걸을 수 있는 타일 중 12%~18%를 덮으며, 멀리서도 읽히도록 자체 오토타일 세트로 그립니다.26 이 비율은 제 선택이지 정전의 수치가 아닙니다. 같은 방식으로 걸을 수 있는 땅 기준으로 세면 정전의 첫 도로는 풀숲이 18.8%~38.4%, 이후 도로는 8.2%~29.2%이므로(1절), 꽃밭은 이후 도로와 같은 수준이고 모든 첫 도로보다 아래에 있습니다. 반짝임은 배치되어 눈에 보이므로, 꽃밭은 그것을 감싸기만 하면 되고 걸음마다 판정을 맡을 필요가 없습니다.17
  • 어떻게 나타나는가. 걸음마다 굴리는 주사위가 아닙니다. 초원 산책로에 들어가면 서버가 그 수집가를 위해 꽃밭 안에 눈에 보이는 반짝임을 최대 하나 놓습니다. 수집가, 날짜, 구역으로부터 결정론적으로 고르며, 동물의 숲의 에이커 진입 규칙을 따릅니다. 이는 그 수집가가 그날 세 개를 받을 때까지입니다.5526 눈에 보이는 반짝임은 아이에게도 규칙을 알기 쉽게 하고, 5절 리듬 행의 쿨다운과 오르막 없이도 연속과 쏠림을 피합니다.
  • 무엇인가. 세계 쪽의 것뿐입니다. 방에 둘 스티커나 액자, 슬리브나 핀 코스메틱, 또는 그날의 퀘스트 하나를 지목하는 메모인데, 그 퀘스트는 진짜 스캔으로만 완료할 수 있습니다. 퀘스트는 이미 컬렉션 자체로 판정됩니다(Kiradex/World/Quests.swift).2765 결코 카드가 아니고, XP도 아니며, 판매하는 물건도 아닙니다. 발견물이 무언가를 살 이유가 되는 일은 결코 없습니다. 코인은 보류합니다. 월드 계획은 매일 방문으로 코인을 얻을 수 있게 하지만 그 양이나 상한은 정하지 않았고, 코인을 네 번째 단계에 두었습니다. 그래서 코인 발견물은 그 규칙이 생길 때까지 미루며, 생기면 추가로 얹는 것이 아니라 같은 일일 방문 예산에서 나오게 합니다.27
  • 누구에게 보이는가. 각 수집가의 반짝임은 그 사람의 것입니다. 함께 걷는 친구들은 각자 자기 것을 봅니다. 빼앗을 것도, 다툴 것도 없습니다.

검사: 10(발견물).

7. 아치와 그 관리인

중앙 광장과 갤러리 지구 사이의 건물은 양쪽에 문이 있고 카운터에 관리인이 있는 8×6 방입니다. 관리인은 수집가의 등록된 카드 수가 처음으로 10, 30, 50, 100을 넘을 때 코스메틱을 건넵니다. 5절 게이트 행의 수집 이정표 관문이며, XP처럼 현실 세계의 컬렉션으로 셉니다.2026 이 방은 그림이 잔디에서 돌로 바뀌는 곳이기도 합니다(5절, 이음매). 잠긴 것은 없습니다. 아치는 늘 열려 있고, 관리인은 주기만 합니다.

검사: 11(아치 관리인).

8. 지도 화면

칸 하나가 10타일이 되도록 반올림한, 이름 붙은 직사각형의 16×12 격자입니다. 중앙 광장 4×3, 그 동쪽에 바인더 거리 4×1, 그 위에 초원 산책로 2×6, 맨 위에 호숫가 4×2, 서쪽에 갤러리 지구 3×2입니다. 호숫가, 초원 산책로, 중앙 광장을 쌓으면 12행 중 11행을 차지합니다(5절, 지도 화면).2617 모든 구역은 첫날부터 그려지고 이름이 붙어 있습니다. 이것은 정전이 아니라 Kiradex 자신의 선택입니다. 네 게임은 지도를 얻은 뒤에는 몇몇 후반 장소를 빼고 모든 장소를 그리지만, 지도 자체는 플레이 도중에 건넵니다(5절, 빠른 이동). 수집하는 마을에는 그것을 볼 권리를 누군가에게 얻어 내게 할 이유가 없습니다. 현재 구역은 맥박처럼 빛나고, 방문한 구역에는 트램 정류장이 표시됩니다. 펼친 Duo에서는 지도를 세계 옆 패널로, 휴대폰에서는 시트로 띄웁니다.27

검사: 8(지도 화면 모델).

9. 트램

야외 구역마다 정류장이 있습니다. 정류장은 수집가가 그 구역에 처음 들어갈 때 열립니다. 5절 빠른 이동 행의 방문 플래그이며, 들어갈 때 켜지고 레벨이나 결제로는 결코 켜지지 않습니다.1326 지도 화면에서 방문한 구역을 탭하면 그곳으로 갑니다. 페이드아웃, 룸 변경, 그 구역 정류장에서 페이드인, 그리고 지명 카드. 실내에서 타는 일은 없습니다. 공중날기가 실내에서 쓸 수 없는 것과 같습니다(5절, 빠른 이동).13 트램은 호숫가까지 걷는 28~30초를, 한 번 걸어 본 뒤에는 탭 한 번으로 바꿉니다. 능력이 아니라 방문으로 얻는 지름길입니다(5절, 개방).26

검사: 9(트램 규칙).

10. 이름과 그림

모든 구역의 이름, 간판, 문자열은 보호된 이름의 금지 목록을 통과해야 하고, 모든 타일과 스프라이트는 포지에서 나옵니다.2726 금지 목록은 아직 없습니다. 조사 자료는 저장소에 그것을 두겠다고 약속했지만 저장소에는 없습니다. 그것을 만드는 일도 이 브리프에 포함됩니다. 보호된 이름을 한 줄에 하나씩 적은 단순한 목록을 포지 옆에 두어 저장소에 체크인하고, 포지 출력물에서 모든 구역의 이름, 간판, 문자열을 읽어 목록의 항목이 대소문자 구분 없이 하나라도 발견되면 실패하는 테스트를 붙입니다.26 번호 붙은 도로 이름, “지방” 식 명명 체계, 정전 게이트의 모양을 재현한 건물은 쓰지 않습니다. 크기와 규칙은 같아도 되지만 모양과 이름은 Kiradex 고유의 것이어야 합니다.26

검사: 13(이름과 그림).

11. 작업 순서

월드 계획은 광장(룸, 동기화, 말풍선, 프로필, 교환 화면)을 세 번째에, 코인과 상점을 네 번째에 둡니다.27 구역은 3b 단계로, 광장의 네트워킹이 안정된 뒤 코인보다 먼저 또는 코인과 나란히 들어갑니다.26

  1. 포지와 서버의 연결(형식, 상호성, 이음매 그리기, 룸 전환), 서버의 8방향 탐색, 그리고 금지 목록과 그 테스트. 첫 구역은 바인더 거리입니다. 건물 작업에서 이미 설계한 카드 가게를 쓰고, 가장 작기 때문입니다.
  2. 초원 산책로와 발견물(서버 배치, 일일 상한, 내용물).
  3. 지도 화면과 트램.
  4. 호숫가.
  5. 미술관 내부가 생기면 아치를 포함한 갤러리 지구. 바인더 거리의 노점 줄은 마켓플레이스 단계를 기다립니다.

월드 계획이 모든 단계에 요구하듯, 각 단계는 TestFlight 빌드이며 그 검사를 위한 캡처를 붙입니다.27

인수 검사

모두 포지 출력물과 서버 테스트에 대한 스크립트로, 또는 시뮬레이터 캡처로 실행할 수 있습니다. 검사 6은 시뮬레이터 캡처 한 번을 빼고 기기에서 실행합니다.26

  1. 상호성. 출력물에 열린 이음매가 정확히 세 개 있어야 합니다. 중앙 광장 동쪽과 바인더 거리, 중앙 광장 북쪽과 초원 산책로, 초원 산책로 북쪽과 호숫가입니다. 그리고 모든 연결 (a, dir, b, off)에 대해 출력물에 (b, opposite(dir), a, −off)가 있어야 합니다. 테스트는 한쪽 연결이 하나라도 있으면 예외 없이 실패합니다.
  2. 경계 넘는 지점. 각 구역의 도착 지점과 문에서 시작한 너비 우선 탐색이, 모든 이음매의 양쪽에서 건너편의 걸을 수 있는 타일을 마주한 경계 타일을 적어도 두 개씩 찾아야 합니다. measure_gen3_routes.py의 방법입니다.6
  3. 거리. 항목 3의 공유 8방향 탐색을, 이어 붙인 구역 위에서 생울타리 문을 일방통행 간선으로 두고(호수 쪽에서 곧은 걸음으로만 들어가고, 호수 쪽으로는 절대 나가지 않음), 모든 길이를 대각선 걸음을 √2로 세는 경로 비용으로 하여 실행했을 때, 도착 지점에서 카드 가게까지 최대 60타일, 도착 지점에서 호숫가 잔교까지 110~120타일, 잔교에서 도착 지점까지 가는 길의 0.8배 이하, 도착 지점에서 미술관 문까지 최대 70타일로 보고해야 합니다. 포지는 초당 4타일 기준 시간을 출력합니다.
  4. 비율. 중앙 광장 너머의 타일 수를 중앙 광장의 타일 수로 나눈 값이 2.0과 3.9 사이여야 합니다.
  5. 방향. 초원 산책로의 높이가 너비보다 커야 합니다.
  6. 이음매에서 검은 프레임도, 메인 스레드 정체도 없을 것. 기기 빌드에서 수집가가 중앙 광장과 바인더 거리 사이의 이음매를 걸어서 넘습니다. 스테이지가 바인더 거리의 메시를 짓기 시작하기 전, 이음매에서 시야의 절반보다 더 떨어진 타일에서 출발해, 이음매를 넘은 첫 걸음이 끝나고 중앙 광장이 뒤쪽 띠가 될 때까지 걷습니다. 두 기록이 그 구간 전체를 다룹니다. 이 실행에서는 ProMotion 디스플레이의 가변 주사율이 걷는 도중에 카운트를 흔들지 않도록, 디스플레이 링크가 preferredFrameRateRange로 60헤르츠를 요청합니다. Apple은 이 범위를 디스플레이 링크가 지키려고 최선을 다하는 범위로 설명하므로, 실제로 유지된 주사율을 보여 주는 것은 요청이 아니라 타이밍 로그입니다.67 첫 번째 기록은 디스플레이가 보여 주는 모든 프레임입니다. 그 주사율로 녹화해 남기고 한 프레임씩 검사합니다. 프레임의 평균 밝기가 구간 중앙값 프레임의 4분의 1 미만이면 검은 프레임으로 보고(이 임계값은 제가 정했습니다), 구간 어디서든 검은 프레임이 한 장이라도 있으면 검사는 실패합니다. 구간 안 녹화의 프레임 수는 같은 구간 타이밍 로그의 콜백 수와 같아야 합니다. 프레임을 떨어뜨리는 캡처가 검은 프레임을 놓쳐서 통과하는 일이 없게 하려는 것입니다. 표시된 모든 프레임을 기록한다고 입증된 캡처 방법은 아직 없으며, 이 일치가 어떤 방법이 그것을 해내는지를 가립니다. 수가 다르고 타이밍 로그가 아래의 자체 규칙을 통과하면 캡처의 결함이므로 그 실행은 치지 않습니다. 수가 다르고 타이밍 로그가 그 규칙을 통과하지 못하면 검사는 실패입니다. 두 번째 기록은, Apple 자신의 예제가 등록하는 것처럼 메인 런 루프에 등록한 CADisplayLink 콜백의 targetTimestamp이며, Apple 문서에 따르면 다음 프레임이 표시되는 시각입니다. 이를 매 프레임 로그로 남깁니다. 연속된 값 사이의 간격은 어느 것도 25밀리초, 즉 60헤르츠에서 1.5프레임을 넘어서는 안 됩니다. 그러면 검은 프레임 한 장처럼 떨어진 프레임 한 장으로도 검사가 실패하고, 경계를 넘을 때뿐 아니라 이웃 구역을 짓는 동안의 메인 스레드 정체도 잡아냅니다. 타이밍 로그가 60헤르츠가 아닌 주사율로 자리 잡은 실행은 치지 않으며, 이 실행에서는 저전력 모드를 끕니다. Apple은 주사율을 바꿀 수 있는 것으로 그 모드, 심각한 발열 상태, 손쉬운 사용 설정을 꼽기 때문입니다.67 기기는 펼친 iPhone Duo가 손에 들어오면 그것입니다. 이 글을 쓰는 지금 제 Mac에 페어링된 iPhone Duo가 없으므로, 그때까지는 같은 이음매에서 iPhone 18 Pro Max로 검사를 실행합니다. 이것으로 휴대폰에서 접근과 경계 넘기가 멈추거나 화면이 꺼지는지는 알 수 있지만, Duo의 안쪽 디스플레이가 프레임을 어떻게 내보내는지는 알 수 없습니다. 시뮬레이터는 대신할 수 없습니다. 제 해석으로는 시뮬레이터의 프레임 타이밍이 재는 것은 그것을 돌리는 Mac이지 휴대폰이 아니기 때문입니다. 이와 별도로, 펼친 Duo 시뮬레이터에서 테스트 번들 내부로부터 캡처했을 때, 수집가가 이음매 직전 중앙 광장의 마지막 타일에 있으면 바인더 거리가 적어도 14타일 보여야 합니다.6064
  7. 지명 카드. 이음매를 넘거나 트램으로 도착한 뒤 2.5~3.5초 동안 카드가 화면에 있어야 합니다.
  8. 지도 화면 모델. 단위 테스트: 모든 구역의 직사각형이 16×12 안에 있고, 둘이 겹치지 않으며, 모든 구역에 이름이 있고, 현재 구역이 표시되며, 방문하지 않은 구역의 정류장은 비활성이어야 합니다.
  9. 트램 규칙. 서버 테스트: 방문하지 않은 구역으로 가는 탑승은 거부됩니다. 실내에서의 탑승은 거부됩니다. 탑승은 목적지 정류장에서 끝납니다.
  10. 발견물. 서버 테스트: 구역에 들어갈 때마다 반짝임은 최대 하나, 수집가 한 명당 하루 최대 셋, 같은 수집가, 날짜, 구역이면 같은 반짝임, 그리고 내용물은 코스메틱과 퀘스트 메모 표에서만 뽑으며 결코 카드, XP, 코인이 아닐 것. 포지 테스트: 꽃밭이 초원 산책로의 걸을 수 있는 타일 중 12%~18%를 덮을 것.
  11. 아치 관리인. 단위 테스트: 이정표 선물 네 개가 등록 수 10, 30, 50, 100에서 각각 한 번씩 발생하고, 코인이나 구매로는 결코 발생하지 않을 것.
  12. 서버 일치. 서버가 모든 구역의 글자와 연결을 불러와, 항목 3의 8방향 탐색으로 수집가를 도착 지점에서 이음매 두 개를 넘어 호숫가 잔교까지 걷게 하고, 생울타리 문을 지나 돌아오게 합니다. 앱과 서버는 양방향 모두에서 같은 타일과 같은 비용을 돌려주어야 하고, 클라이언트의 탐색이 거부하는 걸음(모서리 깎기, 또는 오솔길에서 문을 지나 밖으로 나가는 걸음)은 서버도 거부해야 합니다. 기존 서버 테스트의 패턴입니다.3728
  13. 이름과 그림. 금지 목록이 테스트와 함께 저장소에 있고, 테스트가 통과해야 합니다. 모든 구역 이름, 간판, 문자열이 목록을 통과하고, 모든 타일과 스프라이트가 포지에서 나와야 합니다.

이 브리프에 넣지 않는 것

  • 걸음마다 일어나는 무작위 인카운터, 또는 야생 배틀처럼 플레이되는 모든 것. 발견물은 배치되고 눈에 보입니다.
  • 핵심 구역에 대한 능력 관문. 어느 구역도 레벨, 핀, 구매, 도구로 열리지 않습니다. 구역은 걸어서 가면 열리고, 얻어야 하는 것은 지름길인 트램뿐이며, 그것도 방문으로 얻습니다. 5절 개방 행을 너그러운 쪽으로 읽은 것입니다.5226
  • 트램 없이, 사람들이 모이는 두 장소 사이를 약 30초 넘게 이동하는 것. 정전의 1분짜리 구간은 던전입니다.7
  • 턱, 한쪽으로만 내려가는 단구, 셀 단위 높이. 높이 글로 미루고 거기서 정합니다. 그때까지 브리프는 일방통행이지만 평평한 생울타리 문에서 짧은 귀갓길을 얻습니다.36
  • 번호 붙은 도로 이름, “지방” 식 명명 체계, 배지로 막힌 빠른 이동, 정전 게이트의 모양을 베낀 건물.27
  • 한쪽 연결. 정전은 이를 그리기 요령으로 쓰지만, 이 브리프에는 하나도 없고 검사 1은 하나라도 있으면 실패합니다.8
  • 코인 발견물. 월드 계획이 일일 방문으로 얻는 코인 양을 정할 때까지.27
  • 마켓플레이스 단계 이전의 바인더 거리 마켓플레이스 노점.27

핵심 요약

그림을 그린다면

  • 이음매는 바닥이 이어지는 곳에만 그리십시오. Red는 연결 78개 중 76개에서 같은 타일셋을 잇고, 서로 다른 두 장소를 잇는 Red의 게이트는 모두 타일셋이 바뀌는 자리에 있습니다. 문이 둘인 건물이 재질을 바꾸는 정직한 방법입니다.8
  • 첫 도로는 짧고 풀숲이 가장 많게 하십시오. 화면 2~6장, 맵의 14%~23%를 인카운터 땅으로 하고, 트레이너는 두지 않습니다. 여정이 진행될수록 줄여 나가십시오.56
  • 지도 화면은 이름 붙은 직사각형의 성긴 격자로 그리십시오. Emerald의 것은 28×15칸이고, 직사각형 95개 중 49개가 한 칸입니다.11

엔진을 만든다면

  • 연결은 방향, 이웃, 오프셋을 가진 데이터로 저장하고, 모든 연결에 오프셋을 뒤집은 역방향이 있는지 테스트하십시오. Emerald의 134개는 모두 그렇습니다.842
  • 이웃 구역을 가장자리 너머로 적어도 시야의 절반만큼 그리십시오. 3세대는 플레이어가 좌우로 7셀씩 보기 때문에 7셀(동쪽은 8셀)을 복사합니다. Kiradex의 배율로는 펼친 Duo에서 15타일, 세로 방향 Pro Max에서 12타일입니다.960
  • 이음매에서는 장면을 하나로 유지하고, 장면 교체는 페이드가 가려 주는 문과 빠른 이동에 남겨 두십시오.1037
  • 거리는 자가 아니라 탐색으로, 엔진이 가진 모든 이동 규칙을 넣어 재십시오. 양 끝이 걸어서 이어지는 측정 도로 아홉 개에서 가로지르는 더 긴 쪽 걸음은 긴 변의 1.15~1.70배, 돌아오는 길은 0.95~1.42배이며, 돌아오는 길이 가는 길보다 4분의 1 짧을 수도 있습니다. Crystal의 한쪽 벽과 옆으로 뛰어내리는 모서리 턱을 빼고 탐색하면 Route 32는 양방향 110셀이지만, 넣으면 가는 길 132셀, 돌아오는 길 128셀입니다.5617
  • 앱과 서버에 보행 그래프 하나를 주십시오. 클라이언트는 8방향, 서버는 4방향으로 걷는다면, 테스트가 재는 모든 거리는 그중 한쪽에만 해당합니다.28

루프를 설계한다면

  • 모든 이동을 초로 재십시오. 정전에서 첫 구간은 걸어서 15~25초이고, 1분은 던전입니다.7
  • 돌아오는 길을 가는 길보다 짧게 하고, 그러기 위한 일방통행 장치를 두십시오. 양방향으로 걸을 수 있는 격자에서는 가장 짧은 귀갓길이 곧 가장 짧은 가는 길이기 때문입니다. 정전은 턱으로 그것을 하며 최대 44% 줄입니다. 먼 쪽에서만 열리는 문이라면 높이 없이 그것을 할 수 있습니다.5666
  • 플레이어가 지도를 가지면 모든 장소를 지도에 보여 주고, 얻어야 하는 것은 방문으로 얻는 지름길뿐이게 하십시오. 여기서 측정한 포켓몬 게임은 모두 플레이 도중에 지도를 건네고, 방문 여부와 관계없이 모든 장소를 그리며(스토리나 이벤트 플래그로 가려 둔 몇몇 후반 장소는 예외), 들어갈 때 방문 플래그를 켜고, 빠른 이동에는 방문한 장소만 나열합니다. Kiradex는 한 걸음 더 나아가 첫날부터 지도를 보여 줍니다.4445121323222426
  • 구역은 레벨이나 구매가 아니라 스타듀처럼 행동과 날짜로 열고, 걷는 사람이 어디를 가든 컬렉션으로 할 일을 주십시오.5227

자주 묻는 질문

탑다운 RPG에서 도로는 얼마나 길어야 합니까?

2D 포켓몬 게임에서는 이동 축을 따라 게임기 화면 2~10장, 첫 도로는 2~6장입니다. 셀로 세면 제가 측정한 도로 16개의 긴 변은 20~108셀이고, 끝에서 끝까지 걸을 수 있는 아홉 개에서는 길이 굽이지기 때문에 더 긴 방향으로 가로지르는 최단 걸음이 그 길이의 1.15~1.70배, 돌아오는 길은 0.95~1.42배입니다. 셀당 16프레임으로, 문에서 다음 마을의 주요 건물까지의 첫 구간은 Emerald에서 15.5초, FireRed에서 25.2초가 걸립니다.56717

포켓몬 게임은 로딩 화면 없이 어떻게 맵을 잇습니까?

각 맵은 이웃 맵을 방향과 오프셋과 함께 나열합니다. Emerald에서는 엔진이 현재 맵을 7셀(동쪽은 8셀) 여백을 둔 버퍼에 복사하고(“the player has 7 metatiles of view horizontally in either direction”, 플레이어의 시야는 좌우 각각 7메타타일), 연결된 쪽 여백을 이웃 맵의 7행 또는 7열(동쪽은 8열)로 채워 현재 맵의 타일로 그립니다. 플레이어가 넘어가면 새 맵의 보조 타일셋, 팔레트, 음악, 날씨를 불러오고 지명 표시를 밀어 넣으며, 페이드는 없습니다. Red도 3블록, 6셀 여백으로 같은 일을 합니다.91039

관동의 도로에는 왜 게이트가 있습니까?

데이터에 대한 제 해석으로는, 게임보이의 이음매는 같은 타일셋으로 그린 두 맵만 이을 수 있고, 게이트는 타일셋이 바뀌는 곳의 문이기 때문입니다. Red의 연결 78개 중 76개는 같은 타일셋을 잇고, 서로 다른 두 장소를 잇는 Red의 게이트는 모두 두 타일셋을 잇습니다. 게이트는 규칙도 품습니다. 음료를 원하는 Saffron의 경비원, Route 22의 배지 확인, 그리고 잡은 10종, 30종, 50종에서 도구를 주는 조수 세 명입니다. 타일셋이라는 이유를 확인해 주는 개발자의 발언은 없습니다.8192029

포켓몬의 턱은 왜 한쪽으로만 넘을 수 있습니까?

턱 셀의 동작이 이동 방향 하나를 지정하고, 플레이어는 그 방향으로만 넘을 수 있습니다. 초기 도로에서 측정하면 턱은 앞 마을을 향합니다. 턱이 있고 양 끝이 걸어서 이어지는 도로 아홉 개 모두에서 돌아오는 길이 가는 길보다 2%~44% 짧습니다. 이를 탐색한 도로 네 개에서는 돌아오는 길이 지나는 풀숲이 0~5셀로, 가는 길의 4~19셀과 대조됩니다.365618

공중날기는 날아갈 수 있는 마을을 어떻게 정합니까?

마을에 들어갈 때 켜지는 방문 플래그로 정합니다. Emerald에서는 마을과 도시 16곳이 각자 전환 시 스크립트에서 FLAG_VISITED_* 플래그를 켜고, 지방 지도는 그 플래그가 켜져 있을 때만 마을을 공중날기 목적지로 표시합니다. Red는 wTownVisitedFlag에 도시마다 비트를 두고, Crystal은 맵 콜백에서 공중날기 목적지를 설정합니다. 공중날기에는 배지(Red와 FireRed는 세 번째, Emerald는 여섯 번째)와 야외 맵도 필요합니다.13222423

마을은 길에 비해 얼마나 큽니까?

2~4배 작습니다. 도로 셀 수를 마을 셀 수로 나누면 Crystal은 1.97, Red는 2.65, Emerald의 육지 도로는 3.70, FireRed는 3.87입니다. Emerald의 지도 화면에서는 비율이 5.9 대 1로 읽히는데, 마을은 크기와 관계없이 한두 칸만 차지하기 때문입니다.3334

포켓몬이 도로를 만드는 방식을 따라 해도 합법입니까?

메커니즘, 크기, 방법은 저작권으로 보호되지 않습니다. 구체적인 타일과 스프라이트는 저작권으로, 이름과 표장은 상표권으로 보호됩니다. 이 시리즈의 첫 글이 그 경계를 다루며, 시스템과 작동 방법을 저작권 밖에 두는 미국 저작권청의 Circular 33과, Palworld 개발사를 상대로 한 Nintendo 소송의 특허를 함께 살핍니다.60 이 브리프는 숫자와 규칙을 빌리고, 모든 타일을 Kiradex 자체 포지에서 그리며, 이름은 금지 목록과 대조합니다.26


이 글을 만든 방법. 뒷받침한 조사 자료는 2026년 10월 4일에 pret 디컴파일의 얕은 클론을 출력과 함께 저장한 Python 스크립트 여섯 개로 측정하고, Stardew Valley Wiki, Nookipedia, zladx 디스어셈블리, Porymap 매뉴얼, GBATEK, Pan Docs, Bulbapedia 한 페이지, Apple의 페이지를 저장한 사본을 바탕으로 정리했습니다. 본문의 포켓몬 수치는 모두 스크립트의 출력이며, 각 주석이 그 스크립트를 밝힙니다. 공개 전 10월 5일의 두 번째 검토에서 세 가지 재측정(Crystal의 한쪽 벽과 모서리 점프, 턱을 넘는 달리기, 앱의 8방향 걷기로 본 브리프의 초원)과, 인카운터 코드의 유예 걸음을 더 꼼꼼히 다시 읽는 작업이 있었습니다. 무엇이 바뀌었는지는 각 주석에 적었습니다. 7절의 제안은 제 것이고 그렇게 표시했으며, 그중 어느 것도 아직 만들지 않았습니다.

이 사이트의 관련 글: iPhone에서 만드는 픽셀 아트 세계는 이 시리즈의 첫 글로, 타일 시스템, RealityKit 레시피, 그리고 이 글의 시야가 딛고 선 기기별 타일 수를 다룹니다. 픽셀 아트 인물: iPhone의 캐릭터와 크리에이터는 이 도로들을 걷는 수집가입니다. 픽셀 아트 건물: iPhone의 집, 홀, 실내에는 트램과 아치가 다시 쓰는 문, 워프, 층 교체가 있고, 이 글이 높이 글에 맡긴 턱 거부도 있습니다. 개발자를 위한 iPhone Duo는 시야 절반 띠를 계산하는 바탕인 안쪽 디스플레이의 크기를 도출합니다. iPhone Duo에 맞춰 앱 준비하기는 지도 패널이 따르는 나란히 놓기 레이아웃을 다룹니다. Xcode 27.1 beta: iPhone Duo 시뮬레이터 속의 내 앱은 브리프의 이음매 검사가 돌아가는 시뮬레이터를 다룹니다.

출처


  1. pret, pokered/home/overworld.asm, 커밋 d2704a6(OverworldLoop가 반복마다 DelayFrame을 두 번 호출함. AdvancePlayerSprite가 반복마다 2픽셀씩 8번 움직임, wWalkCounter 8. 자전거에서는 반복마다 AdvancePlayerSprite를 두 번 호출함), 2026년 10월 4일 열람, https://github.com/pret/pokered/blob/master/home/overworld.asm ↩↩↩↩

  2. pret, pokecrystal/engine/overworld/map_objects.asm(StepVectors: 걷기 한 걸음은 2픽셀씩 8틱, 자전거 한 걸음은 4픽셀씩 4틱)와 pokecrystal/engine/overworld/events.asm(MaxOverworldDelay: db 2), 커밋 5beda23, 2026년 10월 4일 열람, https://github.com/pret/pokecrystal/blob/master/engine/overworld/map_objects.asm ↩↩↩↩

  3. pret, pokeemerald/src/event_object_movement.c, 커밋 731ad5b(스텝 테이블: 걷기용 sStep1Funcs 16개 항목, 달리기와 파도타기 8개, 묘기자전거와 물살 6개, 마하자전거 4개, 가장 빠른 것 2개. JUMP_DISTANCE_FAR는 두 셀에 32프레임. sJumpY_High는 정점 12픽셀), 2026년 10월 4일 열람, https://github.com/pret/pokeemerald/blob/master/src/event_object_movement.c ↩↩↩↩↩

  4. Kiradex 소스, Kiradex/World/PlazaRig.swift 101행(tilesPerSecond: Float = 4)과 122행(runPace: Float = 1.6), 2026년 10월 4일 작업 트리에서 열람. 그리고 660행과 666행(매 프레임 한 걸음의 진행에 dt × tilesPerSecond × pace ÷ length를 더하고, 걸음이 끝나면 진행을 0으로 되돌려 넘친 만큼을 버림), 2026년 10월 5일 열람. 비공개 저장소. 초당 6.4타일은 명목상의 달리기로, 4 × 1.6입니다. ↩↩↩↩↩

  5. 저자의 측정, 2026년 10월 4일: measure_gen12_routes.py(이 글을 위한 저자의 증거 폴더에 있음), 출력 gen12_routes.txt. pret pokered(d2704a6)의 입력: constants/map_constants.asm(블록 단위 크기를 두 배로 해 셀로), maps/Route*.blk, Overworld_Coll과 대조한 gfx/blocksets/overworld.bst, 풀 타일 $52와 data/tilesets/ledge_tiles.asm(셀당 8×8 타일 하나, 왼쪽 아래 것), data/maps/objects/Route*.asm(OPP_ 클래스가 있는 object_event 줄을 트레이너로), data/maps/headers/Route*.asm(연결). pret pokecrystal(5beda23)에서: maps/Route*.blk, CollisionPermissionTable을 거친 data/tilesets/<tileset>_collision.asm(블록당 4바이트를 행 우선으로 가정), maps/Route*.asm(OBJECTTYPE_TRAINER를 트레이너로). 2026년 10월 5일 확장(이전 출력은 gen12_routes.pre-walls.txt로 보관): Crystal의 측면 벽, 즉 충돌 바이트 COLL_RIGHT_WALL부터 COLL_UP_LEFT_WALL까지($b0부터 $b7)와 측면 부표는, GetMovementPermissions가 설정하고(home/map.asm, 1511행부터) .CheckLandPerms가 읽는(engine/overworld/player_movement.asm, 686행) 대로, 벽이 있는 쪽으로 나가는 걸음과 그쪽으로 들어오는 걸음을 거부함. 모서리 턱 HOP_DOWN_RIGHT와 HOP_DOWN_LEFT는 아래나 옆으로 뛰어내리며(.ledge_table, 383행), 점프는 평범한 걸음이 실패한 뒤에만 시도됨(.Normal, 45~56행). 점프 비용이 2이므로 최단 경로는 다익스트라 탐색으로 찾음. 측면 벽이 있는 것은 Route 32뿐이고(41셀, 모두 UP_WALL, 그중에 data/tilesets/johto_collision.asm 113행의 블록이 있음), 그 걸음만 바뀌었음: 이전에는 양방향 110, 이후에는 남쪽 132, 북쪽 128. probe_gen12_exact.py(출력 probe_gen12_exact.txt)는 세 변경의 모든 조합을 실행함: 벽만으로 양방향 132, 여기에 양방향 모서리 점프를 더하면 돌아오는 길이 128로 줄고, 정확한 탐색은 아무것도 바꾸지 않음. probe_route32_path.py는 그 점프를 셀 (8, 80)의 HOP_DOWN_RIGHT 가장자리에서 WALL 셀을 넘어 (10, 80)까지 추적함. pokered에는 타일 단위 한쪽 허용이 없음. 그 TilePairCollisionsLand(data/tilesets/pair_collision_tile_ids.asm)는 타일 쌍을 양방향으로 막고 CAVERN과 FOREST 타일셋만 나열하며, 여기서 측정한 맵은 모두 OVERWORLD임. 2세대의 가장자리 해석은 probe_gen2_ledges.py에 따름(Route 30의 HOP_DOWN 셀 21개 중 21개 아래에 WALL 셀이 있음). 1세대 셀 모델은 render_gen1.py가 Red Route 1을 두 배 크기로 16픽셀 격자와 함께 렌더링한 것(render_Route1.png, 분석 전용, 저작권 있는 그림에서 파생되어 공개하지 않음)을 눈으로 보며 확인함. 주석 33의 도로와 마을 면적도 이 스크립트에 따름. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  6. 저자의 측정, 2026년 10월 4일: measure_gen3_routes.py(이 글을 위한 저자의 증거 폴더에 있음), 출력 gen3_routes.txt와 gen3_routes.json. pret pokeemerald(731ad5b)와 pokefirered(037335f)의 입력: data/layouts/layouts.json(크기), 각 도로 map.bin의 모든 셀(비트 0~9 메타타일, 10과 11 충돌, 12~15 높이), 기본 또는 보조 metatile_attributes.bin에서 찾은 그 동작(Emerald는 u16에 동작 비트 0~7, FireRed는 u32에 동작 비트 0~8, 인카운터 종류 비트 24~26), MB_TALL_GRASS, MB_JUMP_*, 물 동작의 개수, 그리고 data/maps/Route*/map.json(연결, trainer_type이 TRAINER_TYPE_NONE이 아닌 object_events를 트레이너로, trainer_sight_or_berry_tree_id). 최단 걸음은 너비 우선 탐색으로 구함. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  7. 저자의 측정, 2026년 10월 4일: measure_travel.py(이 글을 위한 저자의 증거 폴더에 있음), 출력 travel.txt와 travel.json, pret pokeemerald(731ad5b)와 pokefirered(037335f)에 대해. (맵, 셀) 쌍 위에서 이음매, 워프, 턱을 거치는 너비 우선 탐색이며, 첫 문 아래 셀에서 마지막 문까지, 그 문으로 들어서는 마지막 걸음을 포함함(136행, “+1: the step up into the door”, 문으로 들어서는 걸음 +1). 걷기 초는 셀 수 × 16프레임 ÷ 59.7275헤르츠. 달리기는 2026년 10월 5일 확장(모든 달리기 셀을 8프레임으로 친 이전 출력은 travel.pre-ledgerun.txt로 보관)했으며, 한 걸음 8프레임, 턱 점프 32프레임으로 최소 프레임 수를 찾는 두 번째 탐색임. FireRed의 점프는 JUMP_DISTANCE_FAR의 Jump2로 어느 걸음걸이에서든 32프레임이기 때문임(src/field_player_avatar.c의 PlayerJumpLedge, 905행. src/event_object_movement.c의 DoJumpSpriteMovement, 9094행). Route 4 포켓몬센터에서 Cerulean까지의 구간은 점프 한 번을 포함해 2,528프레임, 42.3초이고, 표의 다른 가는 길 구간은 턱을 뛰어내리지 않음. 풀베기 나무, 바위깨기 바위, 괴력 바위는 실행에서 달리 정하지 않는 한 그 셀을 막음(“풀베기 후” 실행은 이를 없애며, Route 2에서는 ROUTE2_EAST_BUILDING이 열림). 페이드와 배틀은 세지 않음. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  8. 저자의 측정, 2026년 10월 4일. 2026년 10월 5일에 FillEastConnection이 복사하는 대로 동쪽은 8열을 읽고, FillNorthConnection, FillSouthConnection, FillWestConnection, FillEastConnection이 자르는 대로 각 띠를 버퍼를 벗어나는 곳에서 자르도록 확장했으며, 기본 전용 수치는 22/38(Emerald)과 25/34(FireRed)에서 24/38과 24/34로 바뀌었음: measure_connections.py(이 글을 위한 저자의 증거 폴더에 있음), 출력 connections.txt와 connections.json, 네 디컴파일 모두에 대해. 모든 맵 연결, 각 이음매를 사이에 둔 타일셋 일치(3세대에서는 기본 및 보조 세트, 그리고 여백에 들어가는 이웃 띠, 즉 7행 또는 7열, 동쪽은 8열이 기본 메타타일만 쓰는지 여부), 오프셋을 뒤집은 상호성, 0이 아닌 오프셋, Red의 GATE 및 FOREST_GATE 타일셋 맵(data/maps/headers/*.asm), Crystal의 환경 GATE(data/maps/maps.asm), 그리고 워프가 서로 다른 두 야외 맵이나 한 야외 맵의 두 쪽으로 이어지는 3세대 실내 맵. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  9. pret, pokeemerald/include/fieldmap.h(MAP_OFFSET 7과 그 주석 “the player has 7 metatiles of view horizontally in either direction”, MAX_MAP_DATA_SIZE 10240, MAP_OFFSET * 2 + 1인 MAP_OFFSET_W와 MAP_OFFSET * 2인 MAP_OFFSET_H), pokeemerald/src/fieldmap.c(InitMapLayoutData가 버퍼를 맵에 MAP_OFFSET_W × MAP_OFFSET_H를 더한 크기로 잡음. FillSouthConnection과 그 형제 함수들. 띠가 들어맞을 때 FillNorthConnection은 x = offset + MAP_OFFSET과 width = cWidth를 설정하고 높이는 MAP_OFFSET행이며, FillEastConnection은 MAP_OFFSET + 1열을 복사함. GetBorderBlockAt은 경계를 MAPGRID_IMPASSABLE과 OR함), data/maps/Route101/map.json(북쪽에 오프셋 0으로 Oldale Town), data/layouts/layouts.json(LAYOUT_ROUTE101과 LAYOUT_OLDALE_TOWN, 둘 다 20×20), 731ad5b, 2026년 10월 4일 열람, https://github.com/pret/pokeemerald/blob/master/include/fieldmap.h 및 https://github.com/pret/pokeemerald/blob/master/src/fieldmap.c ↩↩↩↩↩↩↩

  10. pret, pokeemerald/src/field_camera.c(DrawMetatileAt이 현재 레이아웃의 기본 및 보조 타일셋으로 그림)와 pokeemerald/src/overworld.c(LoadMapFromCameraTransition: 전환 시 스크립트, 보조 타일셋과 팔레트, 음악, 날씨, 지명 표시, 페이드 없음), 731ad5b, 2026년 10월 4일 열람, https://github.com/pret/pokeemerald/blob/master/src/overworld.c ↩↩↩↩↩↩↩↩↩↩

  11. pret, pokeemerald/src/region_map.c(MAP_WIDTH 28, MAP_HEIGHT 15), src/data/region_map/region_map_layout.h, src/data/region_map/region_map_sections.json, 731ad5b, 2026년 10월 4일 열람. 개수는 measure_region_maps.py(출력 region_maps.txt)로 셈. https://github.com/pret/pokeemerald/blob/master/src/data/region_map/region_map_layout.h ↩↩↩↩↩↩↩

  12. pret, pokeemerald/src/field_control_avatar.c(동작이 MB_REGION_MAP인 메타타일이 EventScript_RegionMap을 실행함), data/event_scripts.s(EventScript_RegionMap, special FieldShowRegionMap), data/maps/RustboroCity_DevonCorp_3F/scripts.inc(setflag FLAG_SYS_POKENAV_GET), src/start_menu.c(FLAG_SYS_POKENAV_GET이 켜졌을 때만 나오는 포켓내비 메뉴 항목), src/region_map.c(Battle Frontier와 Southern Island는 FLAG_LANDMARK_* 플래그가 켜질 때까지 MAPSECTYPE_NONE, 1213~1216행), 731ad5b, 2026년 10월 4일 열람. 벽 지도 레이아웃은 scan_wall_maps.py(이 글을 위한 저자의 증거 폴더에 있음, 출력 wall_maps.txt: Littleroot의 두 집 2층과 모든 포켓몬센터 1층)로 찾음. https://github.com/pret/pokeemerald/blob/master/data/event_scripts.s ↩↩↩↩↩↩↩↩

  13. pret, pokeemerald/src/party_menu.c(FLAG_BADGE06_GET에 대응하는 FIELD_MOVE_FLY), src/overworld.c(Overworld_MapTypeAllowsTeleportAndFly), src/region_map.c(마을의 FLAG_VISITED_*가 켜졌을 때 MAPSECTYPE_CITY_CANFLY), data/maps/OldaleTown/scripts.inc(setflag FLAG_VISITED_OLDALE_TOWN), 731ad5b, 2026년 10월 4일 열람, https://github.com/pret/pokeemerald/blob/master/src/region_map.c ↩↩↩↩↩↩↩↩↩↩

  14. Kiradex 소스, scripts/forge/town.py 79행과 80행(MARGIN = 12, WIDTH, HEIGHT = 40, 30)과 그 BUILDINGS 목록(건물 일곱 채, room:me, room:npc-*, hall로 가는 문, 도착 지점 하나), 2026년 10월 4일 열람. 비공개 저장소. ↩↩↩↩↩↩

  15. Martin Korth, GBATEK, LCD 타이밍(“Total 228 lines, 16.743 ms, 280896 cycles - ca. 59.737 Hz”, 총 228라인, 16.743밀리초, 280896사이클, 약 59.737Hz), 2026년 10월 4일 gbatek.txt로 저장, https://problemkaputt.de/gbatek.htm ↩↩↩

  16. Blake Crosley, “Pixel-Art Motion: Walks, Cameras and Doors on iPhone”, blakecrosley.com, 2026년 10월 5일, 7절(“Where the walk stands today”: Kiradex 걷기 코드의 프레임 모델에서 달리기는 60헤르츠에서 타일당 10프레임, 초당 6.00타일, 120헤르츠에서 19프레임, 6.32타일이며, 이는 타일마다 넘친 만큼을 버리기 때문임. 문의 220밀리초 대기와 페이드 없는 층 변경. 그리고 브리프의 걷기, 틱당 1픽셀, 60헤르츠에서 타일당 16틱, 초당 3.75타일과 문과 층을 덮는 단계식 베일), https://blakecrosley.com/blog/pixel-art-motion-on-iphone ↩↩↩↩↩

  17. 본문의 측정값으로 한 저자의 계산. 10월 5일 수치는 arith_oct5.py(이 글을 위한 저자의 증거 폴더에 있음, 출력 arith_oct5.txt)가 출력함: 초당 셀 수는 59.7275 ÷ 16과 ÷ 8. Kiradex의 초당 4타일 대 3.73(7.2% 빠름), 그 달리기 대 7.47은 6.00일 때(19.6% 느림)와 6.4일 때(14.3% 느림). 초당 4타일에서의 시간 대 3.75에서의 시간은 4 ÷ 3.75로 15분의 1 길고, 60헤르츠에서 대각선 23틱 대 √2 ÷ 4초는 0.3833 ÷ 0.3536 = 1.084로 약 12분의 1 김(r6_arith.py가 출력). 셀당 초는 16 ÷ 59.7275(0.27), Kiradex 타일당은 1 ÷ 4(0.25). 경로 계수는 최단 걸음을 도로의 긴 변으로 나눈 값으로, 더 긴 방향과 돌아오는 길에 대해, 각 방향으로 이음매에서 이음매로 가는 걸음이 있는 도로 아홉 개에서 구함(20셀 맵의 첫 행에서 마지막 행까지 곧게 걸으면 19걸음, 0.95). 절약률은 (가는 길 − 돌아오는 길) ÷ 가는 길로 2.38%(Red Route 3)~44.12%(Emerald Route 101). 도로별 걸을 수 있는 셀 대비 풀숲은 두 도로 스크립트의 풀과 걸을 수 있는 셀 수로 계산. Emerald 지도의 마을 칸 수는 region_map_sections.json의 마을 및 도시 구역 16개의 width와 height로 계산(1×1이 열 개, 1×2 또는 2×1이 여섯 개, 모두 22). 안쪽 Duo의 타일 수는 2853 ÷ 96과 2007 ÷ 96이며, 96은 6픽셀짜리 텍셀 16개. 가운데 있는 수집가 앞쪽의 타일 수는 이동 축을 따라 보이는 타일 수의 절반. 100밀리초 표본은 60헤르츠에서 100 × 60 ÷ 1,000 = 여섯 프레임 중 하나. 타이밍 임계값은 60헤르츠에서 두 프레임, 33밀리초. 동물의 숲의 16×16칸짜리 에이커 5×6은 80×96. 브리프의 구역은 44 × 14 + 24 × 60 + 36 × 20 + 30 × 20 = 3,376타일, 40 × 30 = 1,200에 대해. 시야의 절반은 10월 3일 타일 수를 반으로 나누어 올림. 지도 화면 칸 수는 각 구역의 타일 수를 10으로 나누어 반올림. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  18. 저자의 측정, 2026년 10월 4일: measure_grass_paths.py(이 글을 위한 저자의 증거 폴더에 있음), 출력 grass_paths.txt. 풀숲 셀에 들어가면 비용 1, 다른 이동은 비용 0인 0-1 너비 우선 탐색이며, 턱은 한 방향, 두 도로 스크립트의 셀 모델과 문에서 도달할 수 있는 경계 지점을 사용. 대상은 Red Route 1, FireRed Route 1, Emerald Route 101과 102. 입구 셀은 probe_grass_gateway.py(출력 grass_gateway.txt)에 따름. 이는 Red Route 1의 남쪽 방향 탐색을 풀 셀을 하나씩 평범한 땅으로 바꾸어 다시 실행하는 것으로, 최솟값을 낮추는 것은 입구의 마지막 4행에 있는 8셀, 행마다 2셀뿐이었음. ↩↩↩↩↩↩

  19. pret, pokered/scripts/Route5Gate.asm(TEXT_ROUTE5GATE_GUARD_GEE_IM_THIRSTY, BIT_GAVE_SAFFRON_GUARDS_DRINK)과 pokered/scripts/Route22Gate.asm(BIT_BOULDERBADGE), d2704a6, 2026년 10월 4일 열람, https://github.com/pret/pokered/blob/master/scripts/Route5Gate.asm ↩↩↩↩↩

  20. pret, pokered/scripts/Route2Gate.asm, scripts/Route11Gate2F.asm, scripts/Route15Gate2F.asm(임계값 10, 30, 50)과 engine/events/oaks_aide.asm(wPokedexOwned에 대한 CountSetBits), d2704a6, 2026년 10월 4일 열람, https://github.com/pret/pokered/blob/master/engine/events/oaks_aide.asm ↩↩↩↩↩

  21. pret, pokeemerald/src/map_name_popup.c, 731ad5b(POPUP_OFFSCREEN_Y 40, 프레임당 2픽셀의 미끄러짐, tOnscreenTimer > 120), 2026년 10월 4일 열람, https://github.com/pret/pokeemerald/blob/master/src/map_name_popup.c . 합계 190프레임은 태스크의 상태를 임계값으로 센 저자의 계산이며, 각 상태가 한 프레임 길거나 짧을 수 있음. ↩↩↩↩↩

  22. pret, pokered/data/maps/town_map_entries.asm(야외 항목 37개, 그중 하나 미사용. 실내 60개), engine/overworld/toggleable_objects.asm(wTownVisitedFlag, 주석 “mark town as visited (for flying)”), engine/items/town_map.asm(공중날기 목록이 방문하지 않은 마을을 건너뜀), engine/menus/start_sub_menus.asm(공중날기에는 오렌지배지, 비트 2, 와 야외 맵이 필요함), d2704a6, 2026년 10월 4일 열람, https://github.com/pret/pokered/blob/master/engine/items/town_map.asm ↩↩↩↩↩↩↩

  23. pret, pokefirered/src/data/region_map/region_map_layout_kanto.h와 Sevii 레이아웃 세 개(페이지당 22×15, 필드와 던전 층), src/party_menu.c와 include/constants/party_menu.h(공중날기는 FLAG_BADGE01_GET + fieldMove이고 FIELD_MOVE_FLY는 2, 즉 세 번째 배지), src/region_map.c(GetMapsecType은 장소의 FLAG_WORLD_MAP_* 플래그가 켜졌을 때만 MAPSECTYPE_VISITED를 돌려줌, 2957행부터. 공중날기는 방문한 칸만 받음. Sevii 페이지는 FLAG_SYS_SEVII_MAP_123과 FLAG_SYS_SEVII_MAP_4567이 켜질 때까지 가려지며, 1028행과 1556행, 이 플래그는 One Island 포켓몬센터의 스크립트가 켬. Navel Rock과 Birth Island는 FLAG_WORLD_MAP_NAVEL_ROCK_EXTERIOR와 FLAG_WORLD_MAP_BIRTH_ISLAND_EXTERIOR가 켜질 때까지 덧칠됨, 1521~1524행), data/maps/CeladonCity/scripts.inc(전환 시 스크립트의 setworldmapflag FLAG_WORLD_MAP_CELADON_CITY), data/maps/PalletTown_RivalsHouse/scripts.inc(라이벌의 누나가 타운맵을 줌, RECEIVED_TOWN_MAP), data/event_scripts.s(EventScript_WallTownMap, special ShowTownMap), 037335f, 2026년 10월 4일 열람. 개수는 measure_region_maps.py로, 벽 지도는 scan_wall_maps.py(출력 wall_maps.txt: 모든 포켓몬센터 1층, Viridian의 학교, 몇몇 집)로 찾음. https://github.com/pret/pokefirered/blob/master/src/data/region_map/region_map_layout_kanto.h ↩↩↩↩↩↩↩↩↩↩

  24. pret, pokecrystal/data/maps/landmarks.asm(랜드마크 95개), data/maps/flypoints.asm(공중날기 목적지 24곳), maps/VioletCity.asm(VioletCityFlypointCallback: setflag ENGINE_FLYPOINT_VIOLET), engine/events/overworld.asm(ENGINE_STORMBADGE), 5beda23, 2026년 10월 4일 열람, https://github.com/pret/pokecrystal/blob/master/data/maps/flypoints.asm ↩↩↩↩↩↩↩

  25. zladx, LADX-Disassembly, 커밋 2a5c2c0, src/constants/memory/wram.asm(wOverworldRoomStatus, ds $100)과 src/constants/gameplay.asm(OW_ROOM_STATUS_VISITED EQU $80과 다른 상태 비트), 2026년 10월 4일 ladx-wram.asm과 ladx-gameplay.asm으로 저장, https://github.com/zladx/LADX-Disassembly/blob/main/src/constants/gameplay.asm ↩↩↩

  26. 저자의 조사 자료 “Beyond the plaza: routes, map connections and districts in the canon”, 2026년 10월 4일, 4절(“The brief for Kiradex”), 저자의 종합: 다섯 구역과 그 크기, 거리 목표, 연결 형식, 이음매·접속 상태·울타리 틈 계획, 발견물, 아치 관리인, 지도 화면, 트램, 작업 순서, 인수 검사 13개, 그리고 넣지 않는 것. Kiradex 저장소 docs/research/routes/01-routes.md, 비공개. 가는 길 범위는 2026년 10월 5일에 조사 자료의 90~120타일에서 110~120타일로 좁혔으며, 이유는 주석 66에 있음. 조사 자료의 사본에는 아직 이전 범위가 남아 있음. 역시 10월 5일, 조사 자료 이후에 정해져 그 사본에는 없는 것: 앱과 서버가 함께 쓰는 8방향 보행 그래프, 초원의 생울타리 네 줄, 검사 6의 모든 프레임 검사, 해야 할 일로서의 금지 목록, 코인 발견물의 보류. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  27. Kiradex, docs/WORLD.md, “Kiradex World: research and plan”, 2026년 10월 4일 열람(비공개 저장소): 1절(“The rules for Kiradex World”: 세계에 그들의 것은 아무것도 두지 않음), 4절(“Levels”: “XP comes only from the real world, which is the point of the app”. “Coins and the shop”: 코인은 스캔, 레벨, 매일 방문으로 얻음. “The plaza”: 최대 약 40명의 룸을 지역별로 샤딩, 맵 범위 안에 묶여 플레이어를 따라가는 카메라), 5절(“What the Duo gives us”: “The plaza on the open inner display is the best version of this: wide view, your profile card beside the world when you tap someone”), 6절(eBay를 통한 마켓플레이스, 노점), 7절(“Order of work”, 각 단계가 TestFlight 빌드), 그리고 2026년 10월 2일의 결정 사항(FastAPI와 WebSockets로 돌아가는 서버). ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  28. Kiradex 소스, 2026년 10월 5일 열람(비공개 저장소): Kiradex/World/TileMap.swift, 325행부터의 path(from:to:)(여덟 방향 이동. 대각선 비용은 Float(2).squareRoot()이고, 348행에서 통과하는 두 타일이 모두 걸을 수 있지 않으면 건너뜀. 가장 비용이 낮은 열린 타일부터 확장함)와 server/app/rooms.py, 52행부터의 Plaza.path(66행에서 네 방향 이동에 대한 너비 우선. 그 docstring: “the same walk the app takes”). ↩↩↩↩↩

  29. 저자의 조사 자료 “Beyond the plaza: routes, map connections and districts in the canon”, 2026년 10월 4일 정리, “Method” 절과 5절(“What is measured and what is not”): 공통 걷기 정의(한 걸음은 한 셀. 턱은 한 방향이고 두 셀. 이음매는 이웃의 마주 보는 셀에 그 맵의 문 중 하나에서 도달할 수 있을 때만 세며, 워프가 없는 이웃은 다른 연결에서 한 단계 깊이로 시작점을 잡음. 트레이너, NPC, 스토리상 장애물은 무시. 파도타기 없음. 3세대 높이는 같은 높이, 또는 어느 한쪽이 0이나 15인 경우로 단순화. 워프는 밟을 때 발동. 풀베기 나무, 바위깨기 바위, 괴력 바위는 따로 적지 않는 한 막음), 1세대와 2세대 셀 모델의 단서, 지명 표시 타이밍의 단서, 프레임 속도 수치, 분류의 단서, 게임 데이터와 대조하지 않은 2차 자료, 그리고 사실이 아닌 해석. Kiradex 저장소 docs/research/routes/01-routes.md, 비공개이며 저자의 조사 상태 폴더에 사본이 있음. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  30. gbdev, Pan Docs, “Rendering”(프레임당 70,224도트, “@ 59.7 fps”), 2026년 10월 4일 pandocs-timing.txt로 저장, https://gbdev.io/pandocs/Rendering.html ↩

  31. pret, pokeemerald/src/field_control_avatar.c(CheckStandardWildEncounter, 668~686행: sWildEncounterImmunitySteps < 4인 동안은 걸음을 세고 판정 없이 돌아가며, StandardWildEncounter가 성공하면 카운트를 0으로 되돌림), src/overworld.c(LoadMapFromCameraTransition의 RestartWildEncounterImmunitySteps, 800행, 그리고 LoadMapFromWarp, 850행), src/battle_setup.c(배틀 시작 때의 같은 호출, 370행), src/wild_encounter.c(StandardWildEncounter: 동작이 바뀔 때의 40% 건너뛰기, 531~539행과 599행. 502행부터의 WildEncounterCheck: rate의 16배를 마하자전거와 묘기자전거로 80%로, ApplyFluteEncounterRateMod와 ApplyCleanseTagEncounterRateMod로, 그리고 선두 포켓몬의 특성으로 조정한 뒤 그에 대해 Random() % 2880을 판정), src/data/wild_encounters.json(Route 101~104의 육지 rate 20), 731ad5b, 2026년 10월 4일과 5일 열람, https://github.com/pret/pokeemerald/blob/master/src/field_control_avatar.c ↩↩

  32. pret, pokefirered/src/wild_encounter.c, 037335f, 2026년 10월 4일과 5일 열람: GetMapBaseEncounterCooldown(8 − rate/10걸음, 686행). HandleWildEncounterCooldown, 707~755행(마지막 인카운터 이후 걸음 수가 쿨다운에 이르면 모든 걸음이 시도할 수 있음. 그 전에는 인카운터 셀에서의 걸음마다 카운트를 1 늘리고, Random() % 100 < 5일 때 그 한 걸음만 시도하게 하며 쿨다운은 끝내지 않음). TryStandardWildEncounter, 757~776행(카운트와 가산치가 0으로 돌아가는 것은 인카운터가 시작된 뒤뿐). 맵을 불러올 때마다의 같은 초기화: src/overworld.c(764행과 799행)가 RestartWildEncounterImmunitySteps를 호출하고, 이는 FireRed에서 ResetEncounterRateModifiers를 호출함(src/field_control_avatar.c, 735~737행). 새 동작에서의 60% 판정(370행). DoWildEncounterRateTest, 309행(rate × 16에 encounterRateBuff × 16 / 200을 더해 MAX_ENCOUNTER_RATE 1,600에 대해 판정). AddToWildEncounterRateBuff, 778행(벌레회피스프레이가 작동 중이 아니면 판정에 실패할 때마다 rate를 더함), https://github.com/pret/pokefirered/blob/master/src/wild_encounter.c ↩↩

  33. 저자의 측정, 2026년 10월 4일, measure_gen12_routes.py(Red: constants/map_constants.asm에서 $0B 미만인 맵 ID 11개에 대한 ROUTE_1~ROUTE_25, 블록 수 × 4. Crystal: data/maps/maps.asm의 환경 ROUTE 대 TOWN, 크기는 constants/map_constants.asm에서)와 measure_connections.py(Emerald와 FireRed: map_type, 크기는 layouts.json에서. Emerald의 MAP_TYPE_OCEAN_ROUTE 맵 11개, 45,600셀은 육지 수치에서 제외. FireRed의 도로에는 Sevii 제도가 포함됨)로 측정. 출력 gen12_routes.txt와 connections.txt. ↩↩↩↩↩↩

  34. 저자의 측정, 2026년 10월 4일: measure_region_maps.py(이 글을 위한 저자의 증거 폴더에 있음), 출력 region_maps.txt와 region_maps.json(Emerald: 28×15 격자에서 도로 129칸, 마을 22칸). ↩↩

  35. Bulbapedia, “Kanto Route 1”, 공략 절, 2026년 10월 4일 bulba-route1.txt로 저장, https://bulbapedia.bulbagarden.net/wiki/Kanto_Route_1 . 풀 최소화 탐색의 교차 확인으로 한 번만 사용. ↩

  36. 건물 글을 위한 저자의 조사 자료, Kiradex 저장소 docs/research/structures/01-structures-in-the-canon.md, 8.8절(“What to refuse”: “No ledges to jump, no climbing, no isometric”)과 02-structures-craft-and-engine.md(Emerald의 GetLedgeJumpDirection. 턱은 그 동작이 지정하는 방향으로만 넘을 수 있음), 2026년 10월 3일. 비공개. ↩↩↩↩

  37. Blake Crosley, “Pixel-Art Structures: Houses, Halls and Interiors on iPhone”, blakecrosley.com, 2026년 10월 3일(6절: 하나의 깊이 규칙과 오브젝트 메시, 데이터로서의 워프, .id(floor.name)으로 제자리에서 바꾸는 층. 7절: plaza.json에 대한 서버 테스트와 빌드가 하지 않는 일의 목록, 그중 “a one-way ledge”, 일방통행 턱), https://blakecrosley.com/blog/pixel-art-structures-on-iphone ↩↩↩↩↩↩↩

  38. pret, pokered/data/maps/headers/Route1.asm(connection north, ViridianCity, VIRIDIAN_CITY, -5)과 pokered/macros/scripts/maps.asm(connection 매크로의 띠 포인터), d2704a6, 2026년 10월 4일 열람, https://github.com/pret/pokered/blob/master/macros/scripts/maps.asm ↩↩↩

  39. pret, pokered/constants/map_data_constants.asm(MAP_BORDER EQU 3)과 pokered/home/overworld.asm(CheckMapConnections), d2704a6, 2026년 10월 4일 열람, https://github.com/pret/pokered/blob/master/constants/map_data_constants.asm ↩↩

  40. pret, pokered/data/maps/headers/Route22.asm과 Route23.asm(connection north, Route23, ROUTE_23, 0 ; unnecessary와 그 역방향), d2704a6, 2026년 10월 4일 열람, https://github.com/pret/pokered/blob/master/data/maps/headers/Route22.asm ↩

  41. pret, pokecrystal/data/maps/attributes.asm(연결)과 data/maps/maps.asm(타일셋, 환경, 맵 그룹), 5beda23, 2026년 10월 4일 열람, https://github.com/pret/pokecrystal/blob/master/data/maps/attributes.asm ↩

  42. Porymap 문서, “Editing Map Connections”, 2026년 10월 4일 porymap-connections.txt로 저장, https://huderlem.github.io/porymap/manual/editing-map-connections.html ↩↩

  43. pret, pokered/data/maps/objects/Route2Gate.asm(오박사의 조수와 소년), d2704a6, 2026년 10월 4일 열람, https://github.com/pret/pokered/blob/master/data/maps/objects/Route2Gate.asm ↩

  44. pret, pokered/scripts/BluesHouse.asm(EVENT_GOT_POKEDEX가 켜지면 라이벌의 누나가 TOWN_MAP을 주고, 그다음 EVENT_GOT_TOWN_MAP), engine/items/town_map.asm(DisplayTownMap은 방문 확인 없이 TownMapOrder의 모든 항목을 차례로 훑음. wTownVisitedFlag는 BuildFlyLocationsList에서만 읽힘), data/tilesets/bookshelf_tile_ids.asm(bookshelf_tile HOUSE, $3D, TownMapText, 같은 화면을 여는 벽 지도), data/maps/headers/BluesHouse.asm(HOUSE 타일셋의 라이벌 집. 플레이어의 집은 REDS_HOUSE_1과 REDS_HOUSE_2), gfx/blocksets/house.bst(타일 $3D는 블록 14에만 있음), maps/BluesHouse.blk(맨 위 행 두 번째 자리에 블록 14), d2704a6, 2026년 10월 4일 열람, https://github.com/pret/pokered/blob/master/scripts/BluesHouse.asm ↩↩↩↩↩↩

  45. pret, pokecrystal/maps/CherrygroveCity.asm(안내 아저씨의 선물, setflag ENGINE_MAP_CARD, 72행)과 engine/pokegear/pokegear.asm(맵카드의 POKEGEAR_MAP_CARD_F. PokegearMap_CheckRegion은 플레이어가 관동의 랜드마크에 서 있을 때만 관동 지도를 보여 줌. 관동의 공중날기 목적지는 Indigo Plateau를 방문할 때까지 가려짐), 5beda23, 2026년 10월 4일 열람, https://github.com/pret/pokecrystal/blob/master/maps/CherrygroveCity.asm ↩↩↩↩↩

  46. Stardew Valley Wiki, “Modding:Maps”, 2026년 10월 4일 sdv-modding-maps.txt로 저장, https://stardewvalleywiki.com/Modding:Maps ↩↩

  47. Stardew Valley Wiki, “Pelican Town”, 2026년 10월 4일 sdv-pelican-town.txt로 저장, https://stardewvalleywiki.com/Pelican_Town ↩

  48. Stardew Valley Wiki, “Bus Stop”, 2026년 10월 4일 sdv-bus-stop.txt로 저장, https://stardewvalleywiki.com/Bus_Stop ↩

  49. Stardew Valley Wiki, “Cindersap Forest”, 2026년 10월 4일 sdv-cindersap.txt로 저장, https://stardewvalleywiki.com/Cindersap_Forest ↩

  50. Stardew Valley Wiki, “Backwoods”, 2026년 10월 4일 sdv-backwoods.txt로 저장, https://stardewvalleywiki.com/Backwoods ↩

  51. Stardew Valley Wiki, “Railroad”에 표시되는 장소 탐색 상자, 2026년 10월 4일 sdv-railroad.txt로 저장, https://stardewvalleywiki.com/Railroad . 저자가 센 26곳. ↩

  52. Stardew Valley Wiki, “The Mountain”(처음의 출구 두 개, 봄 5일의 광산, 여름 3일 지진 뒤의 철도, 공예실 꾸러미나 25,000g으로 여는 채석장 다리), 2026년 10월 4일 sdv-mountain.txt로 저장, https://stardewvalleywiki.com/The_Mountain ↩↩↩↩

  53. Stardew Valley Wiki, “The Desert”(버스, 금고 꾸러미나 40,000g), “Secret Woods”(통나무와 강철 도끼), “The Beach”(나무 300개짜리 다리), 2026년 10월 4일 sdv-desert.txt, sdv-secret-woods.txt, sdv-beach.txt로 저장, https://stardewvalleywiki.com/The_Desert , https://stardewvalleywiki.com/Secret_Woods , https://stardewvalleywiki.com/The_Beach ↩↩

  54. Stardew Valley Wiki, “Speed”, 2026년 10월 4일 sdv-speed.txt로 저장, https://stardewvalleywiki.com/Speed . 이 페이지에는 단위가 없음. ↩

  55. Nookipedia, “Acre”(16×16칸 에이커, 가로 5에이커 세로 6에이커의 게임큐브판 마을, A-3의 역, 라벨, 진입 시 물고기와 곤충의 출현과 여섯 칸에서의 소멸, 이후 작품의 마을 크기), 2026년 10월 4일 nook-acre.txt로 저장, https://nookipedia.com/wiki/Acre ↩↩↩↩↩

  56. Nookipedia, “Map”, 2026년 10월 4일 nook-map.txt로 저장, https://nookipedia.com/wiki/Map ↩

  57. Nookipedia, “Train”과 “Train station”, 2026년 10월 4일 nook-train.txt와 nook-train-station.txt로 저장, https://nookipedia.com/wiki/Train 및 https://nookipedia.com/wiki/Train_station ↩

  58. zladx, LADX-Disassembly 위키, “Game engine documentation”, 2026년 10월 4일 ladx-engine.txt로 저장, https://github.com/zladx/LADX-Disassembly/wiki/Game-engine-documentation ↩↩↩

  59. zladx, LADX-Disassembly 위키, “Maps data format”(2바이트 방 포인터로 된 512바이트 필드 지도, 10×8 오버레이), 2026년 10월 4일 ladx-maps-format.txt로 저장, https://github.com/zladx/LADX-Disassembly/wiki/Maps-data-format ↩

  60. Blake Crosley, “Pixel-Art Worlds on iPhone: What the 16-Bit Masters Knew”, blakecrosley.com, 2026년 10월 3일(5절: RealityKit 레시피, 맵을 위한 MeshDescriptor 메시 하나, RealityView 기본값, Apple의 사양 페이지와 Xcode 27 시뮬레이터 프로필로 계산한 배율 표, 11포인트 텍스트 최솟값과 SwiftUI 텍스트, 불투명도 애니메이션 버그와 그 베일, 번들 내부 XCUIScreen 캡처. “Since publishing”: 앱과 서버로 내보내는 글자 맵 하나. 저작권과 특허에 관한 FAQ), https://blakecrosley.com/blog/pixel-art-world-on-iphone ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  61. Apple, “iPhone Duo: Technical Specifications”, 2026년 10월 4일 apple-duo-specs.txt로 저장, https://www.apple.com/iphone-duo/specs/ ↩

  62. Apple, 휴먼 인터페이스 가이드라인, “Designing for games”(문서 JSON을 통해), 2026년 10월 4일 hig-games-plain.txt로 저장, https://developer.apple.com/design/human-interface-guidelines/designing-for-games ↩↩

  63. Kiradex 소스, Kiradex/World/PlazaStage.swift, 2026년 10월 5일 열람(비공개 저장소): 132행과 133행(문의 워프에서 Task.sleep(for: .milliseconds(220)) 다음 onWarp(warp), 페이드 없음)과 698~700행(floor: 워프가 새 층을 제자리에서 설정, 페이드 없음). ↩

  64. Apple Developer Documentation, “targetTimestamp”(CADisplayLink의 인스턴스 속성, Core Animation. iOS 및 iPadOS 10.0 이상), 2026년 10월 4일 저장(요약 “The time interval that represents when the next frame displays”, 다음 프레임이 표시되는 때를 나타내는 시간 간격, 그리고 디스플레이 링크를 메인 런 루프에 추가하는 예제), https://developer.apple.com/documentation/quartzcore/cadisplaylink/targettimestamp ↩↩

  65. Kiradex 소스, Kiradex/World/Wants.swift(“What the town’s own collectors ask to be shown, and whether the collection has it”, 마을 수집가들이 직접 보여 달라고 하는 것과 컬렉션이 그것을 가지고 있는지)와 Kiradex/World/Quests.swift(그날과 그 주의 퀘스트, “judged from the collection itself”, 컬렉션 자체로 판정), 2026년 10월 4일 열람. 비공개 저장소. ↩↩

  66. 저자의 측정, 2026년 10월 5일: measure_meadow_gate.py(이 글을 위한 저자의 증거 폴더에 있음), 출력 meadow_gate.txt. 브리프의 중앙 광장, 초원 산책로, 호숫가를 7절의 크기로 한 격자에 합침. 중앙 광장은 포지가 내보내는 그대로(town.json, 40×30, 도착 지점은 19열 13행, 서버의 걸을 수 있는 글자)이고, 공유하는 변을 따라 북쪽 울타리를 엶. 초원 산책로는 24×60으로 중앙 광장 서쪽 끝에서 4타일 안쪽에 두어, 오솔길이 홀과 그 동쪽 집 사이 잔디로 나오게 함. 오솔길은 폭 2타일로 동쪽 생울타리 뒤에 있고, 호수 쪽 끝에 문을 일방통행 간선으로 둠. 나머지는 생울타리 네 줄이 초원의 12, 24, 36, 48행에서 가로지르며, 폭 2타일 틈을 모든 위치에서 시도함. 호숫가는 36×20으로 산책로 가운데에 맞추고, 북쪽 절반은 호수, 잔교는 폭 2타일로 오솔길과 일직선에 두며 육지 쪽 타일까지 잼. 앱의 그래프(TileMap.path)로 걸음: 여덟 방향, 대각선 비용 √2이고 통과하는 두 타일 중 하나라도 막혀 있으면 거부. 문은 오솔길에서 호수 쪽으로 가는 모든 걸음을 거부하고, 호수에서 오는 걸음은 곧은 것만 받음. 굽이는 오솔길 서쪽에서 남쪽 가장자리부터 북쪽 가장자리까지 가는 초원 자체의 최단 걸음. 생울타리 두 줄(초원의 20행과 40행)은 400가지 위치 전부에서 59.00~66.46타일, 세 줄(15, 30, 45행)은 59.00~79.77타일(8,000가지 중 6가지가 78~90), 네 줄은 59.00~95.43타일(160,000가지 중 5,912가지가 78~90). 이 범위는 같은 간격의 생울타리에 대한 것이고, 간격이 고르지 않으면 같은 함수로 더 세게 굽이짐(r7_uneven_probe.py, 10월 5일, 출력 r7_uneven_probe.txt: 0행과 2행의 두 줄은 77.00, 20, 22, 24행의 세 줄은 95.00에 이름). 생울타리 세 줄, 초원의 15, 30, 45행으로 한 같은 탐색(게이트 6라운드 뒤 10월 5일에 스크립트 5절에 추가): 그 레이아웃 6개는 돌아오는 길 88.07타일, 가는 길 114.05~120.44타일, 비 0.731~0.772로 모두 0.8 이하이고, 그중 5개는 110~120 범위 안에 있어 가는 길 114.05~119.02, 비 0.740~0.772. 따라서 세 줄은 5개 위치에서, 저자가 고른 네 줄은 4,111개 위치에서 모든 목표를 충족함. 네 줄 레이아웃 5,912개에서는 돌아오는 길 88.07타일, 가는 길 108.74~133.75타일, 비 0.658~0.810이며 5,886개가 0.8 이하. 0.8 목표에는 88.07 ÷ 0.8 = 110.09의 가는 길이 필요함. 110~120 범위 안에서는 레이아웃 4,111개가 가는 길 110.15~119.95, 비 0.734~0.800으로 모두 0.8 이하. 도착 지점에서 북쪽 가장자리까지는 17.07타일. 문을 양방향으로 열면 걸음은 같아짐(생울타리 줄 수마다 레이아웃 하나에서 양방향 모두 88.07). 0~16타일의 모든 오프셋과 잔교의 두 위치 전부에서 가장 짧은 가는 길은 107.18, 가장 짧은 돌아오는 길은 88.07. 초당 4타일로 110타일과 120타일은 27.5초와 30초. 같은 출력은 이전 모델과도 대조함: 저장한 사본으로 실행하면 생울타리 두 줄의 네 방향 너비 우선 탐색은 레이아웃 125개를 남기며 가는 길 113~119, 돌아오는 길 91, 비 0.765~0.805. 그 125개를 여덟 방향으로 걸으면 가는 길 97.18~99.67, 돌아오는 길 88.07, 비 0.884~0.906으로 0.8인 것은 하나도 없음. 이전 모델은 탐색이 돌려준 어느 최단 경로의 초원 걸음 수를 굽이로 셌는데, 이는 동률일 때 달라질 수 있음. 가장자리에서 가장자리까지의 굽이는 달라지지 않음. 브리프가 서술하지 않은 배치도 같은 출력에서 훑었음: 잔교를 물가 가운데에 두면 가장 좋은 비는 0.721(오프셋 4, 5,912개 중 2,182개가 0.8 이하)이고, 오솔길이 건물에 닿는 배치에서는 문이 아무것도 절약하지 못함. ↩↩↩↩

  67. Apple Developer Documentation, “preferredFrameRateRange”(CADisplayLink의 인스턴스 속성, Core Animation. iOS 및 iPadOS 15.0 이상), 2026년 10월 4일 저장(Discussion: 디스플레이 링크는 그 범위 안에서 콜백하려고 최선을 다하지만, 시스템은 하드웨어, 다른 작업, 저전력 모드, 발열 상태, 손쉬운 사용 설정도 고려하며, 기본값으로 범위는 디스플레이의 최대 주사율과 같음), https://developer.apple.com/documentation/quartzcore/cadisplaylink/preferredframeraterange ↩↩

관련 게시물

Pixel-Art Structures: Houses, Halls and Interiors on iPhone

How Pokémon, the SNES RPGs and Stardew build houses, interiors and floors, measured from source, and how Kiradex's town …

80 분 소요

Pixel-Art People: Characters and a Creator on iPhone

How the best pixel-art games build and dress their people, measured, and how we rebuilt Kiradex's collector, its wardrob…

79 분 소요

iPhone Duo에 맞춰 앱 준비하기: 실제 앱으로 따라가는 예제

iPhone Duo용 앱을 준비하고 제출하는 방법. 레이아웃을 켜는 SDK 스탬프, 모든 포즈로 돌려 본 실제 앱, 스크린샷, App Store 규칙까지 정리했습니다.

53 분 소요