ピクセルアートの道:iPhoneでつくるマップ接続と地区
ポケモンの最初の3世代は、どれも16ピクセルの1セルを16フレームで歩きます。毎秒約3.73セルです。Kiradexのコレクターは毎秒4タイル歩くので、昔のゲームで測った道は、1タイル0.25秒という一定の率で私たちの町に換算できます。1234 各作品の最初の道路はゲーム機の画面2〜6枚ぶんの長さで、トレーナーはいません。最初の区間、つまり自宅の玄関から次の町のポケモンセンターまでは、エメラルドで58セル・徒歩15.5秒、ファイアレッドで94セル・25.2秒です。帰り道はどちらも短く、42セルと76セル。段差がすべて家の方角を向いているからです。567 アートが変わる場所では、カントーは道の上に建物を置きます。赤の78本のマップ接続のうち76本は同じタイルセット同士をつなぎ、異なる2つの場所を結ぶ赤のゲートは、どれも2つのタイルセットをつないでいます。8 ホウエンのエンジンは、隣のマップの7セルぶんを現在のマップの周囲の余白に3辺でコピーし、東側だけは8セルをコピーします。それを現在のマップのタイルで描き、境界を越えた瞬間に隣のマップ固有のセカンダリタイルとパレットを読み込みます。フェードはありません。910 エメラルドのマップ画面は28×15マスのグリッドです。ミシロタウンの自宅2階にある壁の地図で開け、カナズミシティからはポケナビで持ち歩けます。訪れたかどうかに関係なくすべての場所を描き、例外はストーリーのフラグ待ちの2か所だけです。一方、そらをとぶの行き先に並ぶのは、足を踏み入れたときに訪問フラグが立った町だけです。111213 現在のKiradex Worldは40×30の町がひとつあるだけで、柵の外には何もありません。14 そこで、正典(カノン)となる作品群の道、継ぎ目、ゲート、マップ画面を逆コンパイル結果から測り、対照となるモデルとしてStardew Valley、どうぶつの森、ゼルダの伝説 夢をみる島を読み、その数字を、広場の先にある4つの地区、マップ画面、そして初めて着いたときに停留所が開く路面電車のためのブリーフにまとめました。
TL;DR
- 歩行1セルは16フレーム、約4分の1秒です。 赤、クリスタル、エメラルドはいずれも1セルを16フレームで歩き、走りや自転車では8フレームです。ハードウェアの59.7ヘルツでは毎秒3.73セルと7.47セルになります。Kiradexは毎秒4タイル歩く設定で、携帯機より約7%速く、走りは公称6.4ですが、コードのフレームモデルでは60ヘルツで6.00となり、携帯機の走りより約20%遅くなります。1231541617
- 道路の長さは画面2〜10枚ぶんで、最初の道路は短く、くさむらがいちばん多い。 測った16本の道路は、進行方向の軸に沿って2.0画面(エメラルドのRoute 101)から10.0画面(クリスタルのRoute 32)まであります。4本の最初の道路はマップ面積の14.4%〜22.8%がくさむらで、各作品で最も多く、トレーナーはいません。両端が徒歩でつながる9本では、道がうねるため、横断する長いほうの歩きは道路の長辺の1.15〜1.70倍、帰り道は0.95〜1.42倍です。5617
- 段差が帰り道を短くします。 両端が徒歩でつながる9本の道路はすべて段差を持ち、そのすべてで、手前の町へ向かう歩きは2%〜44%短くなります。帰り道で踏まざるをえないくさむらの最少セル数は0〜5で、行きの4〜19と対照的です。5618
- ゲートはアートが変わる場所に立ち、ルールを抱えています。 異なる2つの場所を結ぶ赤のゲートは、どれも2つのタイルセットをつなぎます。ゲートにはバッジの確認、のどの渇いた警備員、そして10種、30種、50種を捕まえたときの3つのごほうびがあります。ホウエンのエンジンは継ぎ目で新しいタイルセットを読み込み、ゲートの建物は4つしかありません。赤ではゲート用タイルセットのマップが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 - マップ画面はすべての場所を示し、ファストトラベルは行ったことのある場所だけを示します。 エメラルドのマップは28×15マスで、そのうち158マスを54の場所が使います。プレイヤーが開けるようになると(まず自宅2階の壁の地図、のちにポケナビ)、訪れたかどうかに関係なくすべての場所を描き、ストーリーのフラグで伏せられた2か所だけが例外です。町がそらをとぶの行き先になるのは、入ったときに
FLAG_VISITED_*フラグが立ったときだけです。赤、ファイアレッド、クリスタル、夢をみる島も同じ種類の訪問記録を持っています。11121322232425 - Kiradexにとっての意味。 中央広場の先にある4つの地区(バインダー通り、草原の小道、湖畔、ギャラリー地区)を中央広場の面積の2.8倍で作るブリーフです。フェードのない開いた継ぎ目、アプリとサーバーで共有する8方向の歩行グラフ、16×12のマップ画面、初めて訪れると停留所が開く路面電車、コスメティックかクエストのメモにしかならない見つけもの、そしてスクリプトかキャプチャで実行できる13の受け入れチェックを含みます。262728
1. 道路を測る
このシリーズの10月3日の3本の記事は、柵の内側にとどまっていました。iPhoneでつくるピクセルアートの世界がタイルシステムとRealityKitのレシピを、ピクセルアートの人物がコレクターを、ピクセルアートの建物が建物とドアを定めました。そこから生まれたKiradex Worldは町ひとつです。40×30タイル、柵の外12タイルまで描かれた森、部屋かホールへ通じるドアを持つ7つの建物、そして到着タイルがひとつ。14 本記事が扱うのは柵の外にあるものです。出発点はこれまでと同じ、逆コンパイル結果です。
以下のポケモンの数値はすべて、pretの逆コンパイルをシャロークローンしたもの(pokered d2704a6、pokecrystal 5beda23、pokeemerald 731ad5b、pokefirered 037335f)から、6本の小さなPythonスクリプトで測りました。どれも1秒前後以内で再実行でき、各数値の裏にあるスクリプトは注に記しています。29 単位はセル、つまり16×16ピクセルの歩行マス1つです。第3世代では1メタタイル、第1世代と第2世代では1ブロックの4分の1にあたります。ゲームボーイの画面は10×9セル(160×144ピクセル)、ゲームボーイアドバンスの画面は15×10セル(240×160ピクセル)を映します。29 歩行モデルはどのスクリプトでも共通です。1歩は1セル。段差はその向きにしか越えられず、1セル先に着地するので移動は2セルぶん。クリスタルでは、タイルの片側の壁を通り抜ける歩みはできず、角の段差は2つの向きのどちらにも飛べます(コードは第2節にあります)。継ぎ目は、隣のマップの向かい側のセルにそのマップのドアのどれかから歩いて行ける場合だけ数えます。トレーナーや他の人物は無視し、なみのりはモデル化していません。29
時計
3世代とも歩く速さは同じです。赤では、OverworldLoopが1回の反復ごとにDelayFrameを2回呼び、AdvancePlayerSpriteが1回の反復で視点を2ピクセル動かし、それを8回繰り返します(wWalkCounterは8)。したがって1セルは16フレームです。自転車ではAdvancePlayerSpriteが1回の反復で2回走るので、1セル8フレームです。1 クリスタルのStepVectorsは、歩きの一歩を2ピクセル×8ティック、自転車の一歩を4ピクセル×4ティックとし、フィールドは2フレームに1ティック進みます(MaxOverworldDelay: db 2)。これもやはり歩きで1セル16フレーム、自転車で8フレームです。2 エメラルドのステップテーブルは、歩き(sStep1Funcs)が16エントリ、走りとなみのりが8、ダートじてんしゃと水の流れが6、マッハじてんしゃの最高速が4、最速が2です。段差のジャンプ(JUMP_DISTANCE_FAR)は2セルに32フレームかかり、頂点で12ピクセル上がります(sJumpY_High)。3
時計のもう半分はフレームです。GBATEKはゲームボーイアドバンスの1フレームを280,896サイクル、「ca. 59.737 Hz」(約59.737Hz)とし、Pan Docsはゲームボーイの1フレームを70,224ドット「@ 59.7 fps」(59.7fps)としています。1530 1セル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タイルでした。1歩ごとに、行き過ぎたぶんの進みを捨ててしまうからです。16 歩きは携帯機の歩きより約7%速く、走りは60ヘルツで携帯機の走りより約20%遅く、公称の6.4でも14%遅くなります。17 歩きは十分に近いので、携帯機のセルで測った距離は一定の率で私たちのタイルに換算できます。道路の所要時間は、携帯機の歩きならセル数×0.27秒、私たちの歩きならタイル数×0.25秒です。17
16本の道路
各作品の最初の4本の道路を測りました。赤のRoute 1〜4、クリスタルの29〜32、エメラルドの101〜104、ファイアレッドの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分の1区画ごとに持つ4つの衝突バイトを読みます。5
| 作品 | 道路 | 大きさ(セル) | 軸方向の画面数 | 歩ける割合 | くさむら、セル数(マップに占める割合) | 段差セル / 段差の列 | トレーナー | 横断の最短歩数、方向別(セル) |
|---|---|---|---|---|---|---|---|---|
| 赤 | 1 | 20×36 | 4.0 | 76.8% | 104(14.4%) | 42 / 10 | 0 | 南へ40、北へ52 |
| 赤 | 2 | 20×72 | 8.0 | 55.9% | 84(5.8%) | 52 / 14 | 0 | 森で分断 |
| 赤 | 3 | 70×18 | 7.0 | 35.1% | 100(7.9%) | 36 / 10 | 8 | ニビ方面82、反対方面84 |
| 赤 | 4 | 90×18 | 9.0 | 45.0% | 60(3.7%) | 169 / 27 | 1 | 洞窟で分断 |
| クリスタル | 29 | 60×18 | 6.0 | 47.7% | 160(14.8%) | 35 / 13 | 0 | 東へ71、西へ90 |
| クリスタル | 30 | 20×54 | 6.0 | 47.6% | 140(13.0%) | 21 / 6 | 3 | 南へ57、北へ74 |
| クリスタル | 31 | 40×18 | 4.0 | 39.3% | 64(8.9%) | 13 / 5 | 1 | 西端はゲート |
| クリスタル | 32 | 20×90 | 10.0 | 48.3% | 152(8.4%) | 6 / 5 | 8 | 南へ132、北へ128 |
| エメラルド | 101 | 20×20 | 2.0 | 59.2% | 91(22.8%) | 13 / 3と角1 | 0 | 南へ19、北へ34 |
| エメラルド | 102 | 50×20 | 3.3 | 48.9% | 143(14.3%) | 17 / 4 | 4 | 東へ55、西へ62 |
| エメラルド | 103 | 80×22 | 5.3 | 27.3% | 92(5.2%) | 24 / 3 | 9 | 海で分断 |
| エメラルド | 104 | 40×80 | 8.0 | 34.0% | 126(3.9%) | 13 / 4 | 8 | 森で分断 |
| ファイアレッド | 1 | 24×40 | 4.0 | 62.3% | 178(18.5%) | 61 / 10 | 0 | 南へ43、北へ58 |
| ファイアレッド | 2 | 24×80 | 8.0 | 40.8% | 84(4.4%) | 44 / 13 | 0 | 森で分断 |
| ファイアレッド | 3 | 84×20 | 5.6 | 37.6% | 117(7.0%) | 42 / 10 | 8 | ニビ方面94、反対方面97 |
| ファイアレッド | 4 | 108×20 | 7.2 | 42.9% | 84(3.9%) | 186 / 28 | 1 | 洞窟で分断 |
表の出典:4つの逆コンパイルに対するmeasure_gen12_routes.pyとmeasure_gen3_routes.py。56 画面数の列は、長辺をその軸に沿ったゲーム機の視界(ゲームボーイなら10セルか9セル、ゲームボーイアドバンスなら15セルか10セル)で割ったものです。歩ける割合の列は、歩く人が立てるセルの割合です。段差セルは、第1世代と第3世代ではジャンプのセル、第2世代では縁のセルです。歩数はドアから到達できる継ぎ目のセル同士で測っています。分断された道路とは、森、洞窟、ゲート、海が両半分のあいだにあるため、マップ内で継ぎ目から継ぎ目への歩きが存在しない道路です。29
長軸方向の道路の長さと、方向別の横断最短歩数。2本の道路スクリプトの出力からfigures/make_figures.pyで描画。
この表から5つのことがわかります。
道路は画面2〜10枚ぶんで、最初の道路は短い。 エメラルドのRoute 101はゲームボーイアドバンスの画面2枚ぶんの高さ、クリスタルのRoute 32はゲームボーイの画面10枚ぶんの高さです。各作品の最初の道路は画面2〜6枚ぶんです。56 セルで数えると、測った道路の長辺は20〜108セルです。6
横断する長いほうの歩きは長辺の1.15〜1.70倍。 16本のうち9本は端から端まで歩けます。その9本について、長いほうの方向の最短歩数を道路の長辺と比べると、エメラルドのRoute 101の北向きが34対20で1.70、クリスタルのRoute 29が90対60で1.50、クリスタルのRoute 32が132対90で1.47、ファイアレッドのRoute 1が58対40で1.45、赤のRoute 1が52対36で1.44、クリスタルのRoute 30が74対54で1.37、エメラルドのRoute 102が62対50で1.24、赤のRoute 3が84対70で1.20、ファイアレッドのRoute 3が97対84で1.15です。5617 帰り道はもっとまっすぐで、長辺の0.95〜1.42倍です。エメラルドのRoute 101が19対20、クリスタルのRoute 30が57対54、ファイアレッドのRoute 1が43対40、エメラルドのRoute 102が55対50、赤のRoute 1が40対36、ファイアレッドのRoute 3が94対84、赤のRoute 3が82対70、クリスタルのRoute 29が71対60、そしてクリスタルのRoute 32が128対90。Route 32は片側の壁のせいで、どちらの方向でも遠回りを強いられます。5617 比が1を下回っても、空間を近道しているわけではありません。20セルのマップで最初の行の継ぎ目セルから最後の行の継ぎ目セルまで歩くと19歩なので、完全にまっすぐな道路は0.95になります。17 私の読みでは、道路の大きさを決めるべき数値は行きのほうです。外枠ではなく、うねる歩きそのもので測るということです。
旅が進むにつれて草は薄くなる。 くさむらは道路のマップの3.7%〜22.8%を占めます。4本の最初の道路、赤の1、クリスタルの29、エメラルドの101、ファイアレッドの1は、それぞれの作品の4本のなかで最もくさむらが多く、14.4%、14.8%、22.8%、18.5%です。2本目の道路は4.4%〜14.3%、3本目と4本目は3.7%〜8.9%です。56 代わりに立てる地面に対する割合で数えると、数値は大きくなり、傾向は平均としてしか成り立ちません。最初の道路は18.8%〜38.4%がくさむらで、残りの12本は8.2%〜29.2%。赤のRoute 3(22.6%)は、足もとでは赤のRoute 1(18.8%)よりくさむらが多いのです。エメラルドのRoute 101では、歩ける237セルのうち91セル、38.4%がくさむらです。5617
最初の道路にはトレーナーがいない。 赤の1、ファイアレッドの1、エメラルドの101、クリスタルの29にはひとりもいません。トレーナーは2本目か3本目の道路から現れ、エメラルドのRoute 102に4人、クリスタルのRoute 30に3人、赤とファイアレッドのRoute 3に8人います。56 これらの道路でのトレーナーの視界は0〜7セルで、エメラルドのRoute 103の9人は1〜5セル、Route 104の8人は0〜7セルを見ています。6
エンカウントの判定は、短い猶予のあと約9歩に1回。 エメラルドは、プレイヤーがマップに入った直後(継ぎ目からでもドアからでも)と戦闘のあとの最初の4歩では判定を行いません。CheckStandardWildEncounterはsWildEncounterImmunitySteps < 4のあいだその歩数を数えるだけで、エンカウントのたびに数え直します。マップの読み込みと戦闘の開始でもやはり数え直しです。その後は、エンカウントのあるセルに踏み込むたびに判定が行われます。異なる挙動のセルに移る一歩では40%の確率で判定を飛ばし、それからRandom() % 2880 < rate × 16です。Route 101〜104はすべてrate 20なので、補正なしの判定は2,880分の320、徒歩で1歩あたり11.1%です。自転車、ビードロ、きよめのおふだ、一部の先頭ポケモンの特性は、その前に率を変えます。31 ファイアレッドは下限と上り坂を加えます。エンカウントのあとやマップに入ったときに、エンカウントのあるセルで8 − rate/10歩(Route 1〜4のrate 21なら6歩)のクールダウンがあり、その各歩で5%の判定に当たると、クールダウンを終わらせないままその1歩だけエンカウントを試せます。次に新しい挙動のセルでの60%の判定、それから1,600分のrate × 16、つまり21%で、判定に失敗するたびにrateぶん増えていく上乗せ(encounterRateBuff)が加わります。32 私は、この猶予と下限と上り坂を、出会いの日照りと洪水の両方を短く保つための仕組みだと読んでいます。Kiradexには野生のバトルがないので、この数値はリズムとしてだけ意味を持ちます。最初の数歩を過ぎれば、最初の道路はくさむらを約9歩進むごとに何か気づくものを差し出す、ということです。
世界のどれだけが道なのか
| 作品 | 道路マップ数 | 道路のセル数 | 町のマップ数 | 町のセル数 | 道路対町 |
|---|---|---|---|---|---|
| 赤 | 25 | 31,500 | 11 | 11,880 | 2.65 |
| クリスタル(ジョウトとカントー) | 54 | 49,880 | 23 | 25,380 | 1.97 |
| エメラルド(陸の道路) | 41 | 87,787 | 16 | 23,700 | 3.70 |
| ファイアレッド(ナナシマを含む) | 57 | 98,451 | 19 | 25,470 | 3.87 |
道は町の2〜4倍の面積を持っています。33 エメラルドの11本の水道を加えると、さらに45,600セル増えます。33 この比はマップの分類のしかたで変わり、作品ごとに分類が異なります。赤はマップIDと名前、クリスタルは環境(たとえばROUTE環境にはアルフのいせきの屋外が含まれます)、エメラルドとファイアレッドはmap_typeで分類しており、ファイアレッドの道路にはナナシマが含まれ、エメラルドの道路からは海が除かれています。33 エメラルドのマップ画面では、同じ世界が道路129マス対町22マス、5.9対1と読めます。町は大きさにかかわらず1マスか2マスしか取らないからです。16の町と市のうち10は1マス、6は2マスです。341117
Route 1を3通りに
赤、ファイアレッド、クリスタルは同じ考えを3つの解像度で描いており、Route 1がいちばんすっきり比較できます。赤のRoute 1は10×18ブロック、20×36セル、ゲームボーイの画面4枚ぶんの高さで、柵の支柱と木の列のあいだに南向きの段差が10列、計42セルあり、草は104セルです。5 第1世代のセルモデルを確かめるため、このマップひとつだけをブロックセットから2倍の大きさで16ピクセルのグリッド付きで描画しました。すると西側の木の列の外に幅3セルの開けた地面があり、両方の継ぎ目に接しているのに、どちらの町のドアからも到達できないことがわかります。探索が隣の町のドアから横断点を起こしているのはこのためです。5 第1世代のモデルは1セルにつき8×8タイルを1つ、左下のものだけを読みます。確認したのはこの描画を目で見た範囲だけで、水と陸のペアのようなタイルペアの衝突はモデル化していません。29
ファイアレッドのRoute 1は24×40セルで、大きくなった画面でもやはり4枚ぶんの高さです。段差は61セル、草は178セルでマップの18.5%。リメイクは画面数で見た長さを保ち、マップを各方向に4セル広げ、段差を増やしました。6 マサラタウンの玄関からトキワシティのポケモンセンターまでは94セル、25秒で、逆方向は76セルです。7 クリスタルの最初の道路であるRoute 29は60×18セル、ゲームボーイの画面6枚ぶんの幅で、草は14.8%、トレーナーはいません。ワカバタウン側からヨシノシティ側への横断は90セル、帰りは71セルです。5
2. ドアからドアへ、そして帰り道
道路そのものの長さは、旅の一部にすぎません。プレイヤーが感じるのは区間です。ある建物を出て、町を抜け、道路と次の町を横切り、次の建物に入るまで。measure_travel.pyは、その道のり全体を(マップ, セル)の組の上で、継ぎ目、ワープ、段差を通して探索します。出発点は最初のドアの下のセル、終点は最後のドアで、そこへ踏み込む一歩も数えます。7
| 作品 | 出発 | 到着 | セル | 徒歩 | 走り | 通過するマップ |
|---|---|---|---|---|---|---|
| エメラルド | ミシロタウン、自宅 | コトキタウンのポケモンセンター | 58 | 15.5秒 | 7.8秒 | 町、道路、町 |
| エメラルド | コトキタウンのポケモンセンター | トウカシティのポケモンセンター | 87 | 23.3秒 | 11.7秒 | 町、道路、市 |
| エメラルド | トウカシティのポケモンセンター | カナズミシティのポケモンセンター | 250 | 67.0秒 | 33.5秒 | 市、道路、森、道路、市 |
| ファイアレッド | マサラタウン、自宅 | トキワシティのポケモンセンター | 94 | 25.2秒 | 12.6秒 | 町、道路、市 |
| ファイアレッド | トキワシティのポケモンセンター | ニビシティのポケモンセンター | 267(いあいぎり後は156) | 71.5秒(41.8秒) | 35.8秒 | 森の2つのゲートを通る |
| ファイアレッド | ニビシティのポケモンセンター | Route 4のポケモンセンター | 150 | 40.2秒 | 20.1秒 | 市、道路、道路 |
| ファイアレッド | Route 4のポケモンセンター | ハナダシティのポケモンセンター | 314 | 84.1秒 | 42.3秒 | 洞窟の3つの階を通り、うち1つは2度通る |
徒歩の秒数は、セル数×16フレームを59.7275ヘルツで割ったものです。走りは、最少フレーム数を求める2回目の探索で、1セル8フレーム、ただし段差のジャンプは引き続き32フレームです。ジャンプはどの歩調でも同じ32フレームのジャンプだからです。上の7区間のうち段差を飛ぶのは洞窟の区間だけで、それも1回なので、2,512フレームではなく2,528フレームになります。「いあいぎり後」の数値は、Route 2の5本のいあいぎりの木を取り除いた同じ探索で、これによりROUTE2_EAST_BUILDINGを通る東の道が開きます。フェードと戦闘は数えていません。7 探索の単純化のうち、洞窟の区間で特に効いてくるものが2つあります。第3世代の高さを2つの場合(同じ高さか、どちらかが0か15)に簡略化していること、そしてワープを、到着したときではなく踏み込んだときに発動させていることです。そのため、1F、B1F、B2F、そしてもう一度B1Fを通る洞窟経由の314セルは、表のなかで最も不確かな数値です。29
ドアからドアまで、行きと、測った場合は帰りも。ブリーフの目標を正典の横に並べた。travel.jsonからfigures/make_figures.pyで描画。
最初の区間は徒歩15〜25秒。 自宅のドアから次の町のポケモンセンターまで、エメラルドは58セル・15.5秒、ファイアレッドは94セル・25.2秒です。7 1分に届く区間(エメラルドの250セル、ファイアレッドの267セルと314セル)は森か洞窟を通ります。私の読みでは、それらは道ではなくダンジョンで、ダンジョンはそれ自体がひとつの種類の場所です。
帰り道は短い。 コトキタウンのポケモンセンターからミシロタウンの自宅までは、行きの58セルに対して42セル。トキワからマサラは94に対して76、トウカからコトキは87に対して81、カナズミからトウカは250に対して196、ニビからトキワは267に対して254です。7
ひでんマシンは、すでに前を通り過ぎたゲートを抜ける近道です。 Route 2のいあいぎりの木を取り除くと、トキワからニビまでは267セルではなく156セルになり、道は森ではなくRoute 2の東の建物を抜けます。7
ホウエンの最初の3区間
エメラルドは、町と町のあいだに何があるのかという問いに3つの異なる答えを出して始まります。測ってみると、その設計が読み取れます。
Route 101は、両端に玄関のある通路です。20×20セル、画面2枚ぶんの高さで、くさむらは22.8%、立てる237セルのうち91セルです。南向きの4セルの段差が3列、道路を横切っています。ミシロタウンから北へ歩くと34セルで、少なくとも10セルの草を通ります。コトキタウンから南へ歩くと19セルで、段差を飛び降りれば草をまったく踏まずに済みます。自宅の玄関からコトキタウンのポケモンセンターまでは58セル、徒歩15.5秒です。6187
Route 102は幅が広く、最初のトレーナーがいます。50×20セル、画面3.3枚ぶんの幅で、草は14.3%、視界2〜3セルのトレーナーが4人、水のセル26の池、段差のセルが17あります。トウカシティは−10のオフセットで接続しているので、道路の20行はトウカシティの10〜29行目に面しています。ポケモンセンターからポケモンセンターまで、コトキからトウカは87セル・23.3秒、帰りは81セルです。67
Route 104は2つに分かれた道路です。40×80セル、画面8枚ぶんの高さで、4分の1が水、マップ内には3つの継ぎ目をつなぐ歩きがありません。南半分はトウカのもりの南口に通じ、トウカシティの継ぎ目から51セル。北半分は森の北の出口に通じ、カナズミシティの継ぎ目から出口の2つの戸口セルのうち近いほうまで60セル(もう一方までは61セル)です。トウカシティのポケモンセンターからカナズミシティのポケモンセンターまでは5つのマップ(市、道路、森、道路、市)を通って250セル、徒歩67秒、帰りは196セルです。67
3つのあいだで変わるのは分母です。最初の道路は20秒未満の歩きで、トレーナーはおらず、帰りは草を踏まずに済みます。3つ目はダンジョンを抜ける1分の歩きです。私の読みでは、このゲームはプレイヤーが歩くことを覚えてから初めて距離を使います。
段差は家を向く
両端が徒歩でつながる測定済みのすべての道路の行きと帰り、そして方向別の最少の草セル数。道路スクリプトの出力とgrass_paths.txtからfigures/make_figures.pyで描画。
両端が徒歩でつながる測定済みの道路では、9本すべてに段差があり、そのすべてで手前の町へ向かう歩きのほうが短くなります。赤のRoute 1は行き52セルに対して帰り40セルで23%短く、ファイアレッドのRoute 1は58に対して43で26%、エメラルドのRoute 101は34に対して19で44%、エメラルドのRoute 102は62に対して55で11%、クリスタルのRoute 29は90に対して71で21%、クリスタルのRoute 30は74に対して57で23%です。赤のRoute 3は84に対して82、ファイアレッドのRoute 3は97に対して94、クリスタルのRoute 32は132に対して128で、いずれも2%〜3%です。Route 32の4セルの差は、角の段差を横向きに1回飛ぶことから生まれており、帰り道で飛ぶのはその1回だけです。5617 最初の道路の段差はすべて同じ方向を向いています。赤のRoute 1の10列42セル、ファイアレッドのRoute 1の10列61セル、エメラルドのRoute 101の13セル(4セルの列が3つと角のセル1つ)はすべて南向きで、角は南東向きです。どのマップでも、それは出発した町へ戻る方向です。56
段差は帰り道から草も取り除きます。歩数ではなく踏むくさむらのセル数を最小にする2回目の探索によると、赤のRoute 1を北へ歩く人は少なくとも15セルの草を通らなければなりませんが、南へは4セルだけで、そのすべてがマサラタウン脇の入り口にあります。ファイアレッドのRoute 1は19対5、エメラルドのRoute 101は10対0、エメラルドの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 これは一度だけ、探索の照合として使ったwikiのページです。探索はマサラタウン脇の入り口を除いてこの記述と一致します。その入り口は幅2セル、草が4行の深さなので、セルモデルでは南向きのどの歩きもそこで1行に1セル、計4セルの草を通ります。段差は道路上のほかの草をすべて迂回させますが、完全にすべてではありません。18
第2世代の数値には、それぞれひとつずつ注意書きが要ります。クリスタルの衝突は32ピクセルのブロックごとに4バイト、4分の1区画ごとに1バイトで、スクリプトはそれが行優先の順(左上、右上、左下、右下)に並ぶと仮定しています。tilecollマクロが順序を明示していないからです。29 第2世代のCOLL_HOP_*バイトは、その先のセルではなくプレイヤーが立つ縁のセルを示します。これはprobe_gen2_ledges.pyがRoute 30の21個のHOP_DOWNセルすべての下にWALLセルがあることを見つけて確定させました。縁という読みを確かめたのはRoute 29と30だけです。529 クリスタルには片側の壁もあります。COLL_RIGHT_WALLからCOLL_UP_LEFT_WALLまでの衝突バイトは陸ですが、GetMovementPermissionsは、そのタイルから壁のある側を通って出る一歩も、その側から入る一歩も拒みます。4本のうちこれを持つ唯一の道路であるRoute 32(41セル、すべてUP_WALL)では、これを無視する探索なら両方向とも110セルの最短歩数が、行き132セル、帰り128セルに延びます。その角の段差HOP_DOWN_RIGHTとHOP_DOWN_LEFTは、ふつうの一歩が拒まれると、プレイヤーの向きに応じて下か横に飛び、帰り道はそのひとつを横向きに飛びます。赤には片側の壁はありません。赤のもうひとつの移動規則であるタイルペアの衝突は双方向に働き、洞窟と森のタイルセットにしか登録されておらず、ここで測ったマップはどれもそれを使っていません。5 また探索は段差を2セルぶんの移動として数えます。これは第3世代の32フレームのジャンプと一致し、第1世代と第2世代については仮定です。293
データが示しているのは結果であって意図ではありません。段差が帰り道を短くするように置かれたという開発者の発言は見つかっておらず、わかっているのは、測ったすべての道路でそうなっているということだけです。29 私がそこから取り出すルールは、段差は帰りのための一方通行の近道であって、決して行く手をふさぐ壁ではない、というものです。
高さの問題
この発見は前回の記事と相性がよくありません。ピクセルアートの建物の背後にある建物の調査ドシエは、段差をきっぱり拒否していました。「No ledges to jump, no climbing, no isometric」(飛び降りる段差なし、よじ登りなし、アイソメトリックなし)。そしてその記事は、ビルドがやらないことのひとつに一方通行の段差を挙げています。3637 今回のドシエは、段差を正典における帰り道の近道として測っています。両者は事実について対立しているわけではありません。食い違っているのは、コレクションの町がその効果を得るために高さを必要とするかどうかです。その判断は、このプログラムの次の記事、高さ、段差、橋を扱う記事のものですが、まだ公開されていません。そこで決まるまで、第7節のブリーフは段差を高さの記事に先送りし、帰り道の短縮は生け垣の門から得ます。草原の小道にある、湖の側からしか開かない門です。高さを持たない、同じ一方通行の帰り道の近道です。26
3. 継ぎ目、ゲート、マップ画面
ポケモンのフィールドは1枚の大きなマップではありません。それぞれ固有の大きさ、タイル、音楽を持つ多数の小さなマップが辺と辺で結ばれ、切れ目なく次のマップへ歩いていけるようになっています。この結合のしくみが、この節のほとんどすべてを決めます。どこで道の上に建物を立てなければならないか、なぜリメイクではそれが少ないのか、そしてマップ画面が何を知りうるのか。
第1世代と第2世代:余白にコピーされる帯
赤の接続は、マップのヘッダーにある1行です。方向、隣のマップ、ブロック単位のオフセットを指定します。Route 1のものはconnection north, ViridianCity, VIRIDIAN_CITY, -5で、マクロは隣のマップのブロックのどの帯を現在のマップのバッファにコピーするかを前もって計算します。38 バッファwOverworldMapは、マップの四方すべてにMAP_BORDER EQU 3ブロック、つまり6セルの余白を持ちます。接続はその余白を隣のマップのいちばん近い3行または3列のブロックで埋め、CheckMapConnectionsは、プレイヤーの座標が−1かマップの幅または高さを越えたときにマップを切り替えます。39
帯はブロック番号としてコピーされ、そのとき読み込まれているブロックセットで描かれるので、2つのマップが継ぎ目で接するには同じタイルセットを共有していなければなりません。赤のデータはそれを守っています。78本の接続行のうち76本は同じタイルセットのマップ同士をつないでいます。例外の2本はRoute 22とRoute 23(OVERWORLDとPLATEAU)で、ヘッダーファイルはどちらの行にも「; unnecessary」(不要)と注記しています。840 クリスタルには142本の接続行があります。138本は同じタイルセット同士をつなぎ(例外はコガネシティとRoute 35、Route 32とRoute 33で、JohtoとJohto Modernの組み合わせ)、92本はひとつのマップグループのなかに収まっています。841
第3世代:隣のマップを7セル(東は8セル)、アートは越えた瞬間に
第3世代の接続は、マップのmap.jsonにあるmap、offset、directionのエントリです。エメラルドには上下左右のエントリが134個と、ダイビングと浮上のエントリが14個あり、134個のすべてに、オフセットの符号を反転させた逆向きのエントリが対応しています。8 逆コンパイルのコミュニティが使うマップエディタPorymapは、この機能を3つの文で説明しています。「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.」(接続は一方向なので、2つのマップのあいだの2つの接続を同期させておく必要がある)。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
継ぎ目でバッファが保持するものの模式図。1セルを1マスとし、MAP_OFFSET、FillNorthConnection、Route 101の20×20のレイアウトと、その北にオフセット0で接するコトキタウンの幅20のレイアウトから寸法を取った。figures/make_figures.pyで描画、ゲームのアートは使っていない。
隣のマップの帯は、プレイヤーが越えるまで現在のマップのタイルセットで描かれます(DrawMetatileAtは、いま立っているマップのプライマリとセカンダリのセットを取ります)。越えるとLoadMapFromCameraTransitionが呼ばれ、新しいマップの切り替え時スクリプトを実行し、そのセカンダリタイルセットとパレットだけを読み込み、音楽と天気を変え、地名の表示を出します。フェードはありません。10 だからこそ、プライマリタイルセットが異なる接続の組はひとつもありません。エメラルドの134組のうち0組、ファイアレッドの120組のうち0組です。セカンダリタイルセットが異なるものはエメラルドで38組、ファイアレッドで34組あり、それぞれ24組では、余白に入る隣のマップの帯(7セル、東は8セルで、バッファからはみ出すところはエンジンと同じく切り落とす)がプライマリのメタタイルだけを使っているので、どちらの側からでも正しく描かれます。8
オフセットはありふれています。エメラルドの134の接続のうち36、ファイアレッドの120のうち68がゼロではありません。ファイアレッドのRoute 1は、トキワシティの48セルの幅のうち12セル内側に位置しています。8 ファイアレッドでは、相互性は完全に普遍というわけではありません。120のエントリのうち112は相互で、残り8つのうち6つは城壁に囲まれた都市によるものです。ヤマブキシティはRoute 5〜8に一方向に接続していますが、それらの道路はヤマブキシティではなく、別のSAFFRON_CITY_CONNECTIONマップに接続しています。最後の2つはナナシマの試作マップです。8 私はこのヤマブキシティの配置を描画上の工夫だと読んでいます。この接続は道路の端の向こうに市の城壁を描くために存在し、入口は4つのゲートで、赤ではその警備員が飲み物をもらうまでプレイヤーを追い返します。819 連続して見えなければならず、それでいて関門が必要な場所では、第3世代は余白に隣を描き、扉を建物のなかに置くのです。
show_map_nameが設定されたマップへ継ぎ目を越えると、その場所の名前がスライドして現れます。表示タスクは31フレーム待ち、1フレーム2ピクセルで40ピクセルをスライドして入り(20フレーム)、タイマーが120を超えるまでとどまり(121フレーム)、スライドして出ていきます(20フレーム)。合計約190フレーム、3.2秒です。21 タスクの各状態はしきい値から数えたので、それぞれ私の数より1フレーム長いか短い可能性があります。29
ゲート:アートが変わる場所
赤には、GATEかFOREST_GATEのタイルセットを使うマップが27枚あります。Route 11、12、15、16、18の2階建てのゲート(10マップ)、Route 2、5、6、7、8の1階建てのゲート、Route 22のゲート、サファリゾーンのゲートとその4軒の休憩小屋、4つのちかつうろの入口、そしてトキワのもりの2つのゲートです。8 異なる2つの場所を結ぶ赤のゲートは、どれも2つのタイルセットをつなぎます。OVERWORLDからFOREST(トキワのもり、サファリゾーン)、UNDERGROUND(4つの地下通路の入口)、あるいはPLATEAU(Route 22からRoute 23)へ。赤の接続がほとんど作ることのない結合です。8
いちばんわかりやすいのはRoute 2です。赤では20×72セル、ファイアレッドでは24×80セルで、端から端まで歩くことはできません。南半分と北半分はトキワのもりを通じてしかつながっておらず、赤ではこの森はOVERWORLDではなくFORESTのタイルセットで描かれ、2つのゲートから入ります。58 ファイアレッドでは、トキワシティのポケモンセンターからニビシティのポケモンセンターまで、南のゲート、森、北のゲートを通って267セルです。7 ここから3つの読みが導かれますが、それはデータの読みであって、開発者の発言ではありません。
- ゲートはアートが変わる場所。 第1世代の継ぎ目は隣のマップのブロックを現在のブロックセットで描くので、2つのマップが継ぎ目で接するにはタイルセットを共有していなければならず、赤は78の接続のうち76でそれを守っています。森のタイルセットで描かれた森にはしたがって扉が必要で、ゲートがその扉です。388
- ゲートはルールが住める場所。 4つのヤマブキのゲートは、飲み物を渡すまでプレイヤーを追い返します(
TEXT_ROUTE5GATE_GUARD_GEE_IM_THIRSTY、BIT_GAVE_SAFFRON_GUARDS_DRINK)。Route 22のゲートはBIT_BOULDERBADGEを確認します。19 さらに3つのゲートはコレクションに報います。オーキド博士の助手たちは、捕まえた種類の数(wPokedexOwnedに対するCountSetBits)が、Route 2のゲートで10、Route 11のゲートの2階で30、Route 15のゲートの2階で50に達すると道具をくれます。20 - ゲートは人のいる小休止。 Route 2のゲートにはオーキド博士の助手と少年がいます。歩きはフェードのあと、新しい場所で再開します。43
リメイクはエンジンによって分かれます。クリスタルには環境GATEのマップが25枚あり、そのうち19枚は異なるマップグループのマップ同士を、7枚は異なるタイルセット同士をつないでいます。8 ファイアレッドはカントーのゲートを保っています。8つの屋内マップが2つの異なる屋外マップへ通じ(トキワのもりの1組、ヤマブキの4つの入口、Route 22の北の入口、サファリの入口)、さらに13がひとつの屋外マップの2つの別々の側にドアを持ちます。そのなかには5つの2階建ての道路ゲートとRoute 2の東の建物が含まれます。8 ホウエンはゲートをほぼなくしています。エメラルドで2つの異なる屋外マップへ通じる屋内マップは2つだけ(おくりびやまの1階とサファリゾーンの入口)で、ひとつの屋外マップの2つの側にドアを持つものが5つ、そのなかに2つのサイクリングロードの詰所があります。道路と町は開いた継ぎ目で接しています。8 建物として数えると、エメラルドのゲートは4つ(2つのサイクリングロードの詰所、サファリゾーンの入口、バトルフロンティアのゲート)で、ファイアレッドは14、赤はゲート用タイルセットのマップが27です。8 私の読みであり、あくまで読みですが、ホウエンがゲートをなくせたのは、エンジンが越えた瞬間に新しいセカンダリタイルセットを読み込むので、異なるアートで描かれた町と道路があいだに建物を挟まずに接することができるからです。10
マップ画面とそらをとぶ
エメラルドの地方マップは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は1マスだけで、最大は4×3(Route 124とその海底の双子)、カイナシティは1×2、キンセツシティは2×1です。11 この証拠からすると、マップ画面とは名前のついた長方形を並べた粗いグリッドであり、ほとんどの場所は1マスです。
そらをとぶは、画面と歩きが出会う場所です。エメラルドのそらをとぶには6つ目のバッジ(バッジ表でFIELD_MOVE_FLYに対応するFLAG_BADGE06_GET)と、屋外のマップタイプ(Overworld_MapTypeAllowsTeleportAndFly:道路、町、市、水道)が必要です。マップ上で町がMAPSECTYPE_CITY_CANFLYになるのは、そのFLAG_VISITED_*フラグが立っているときだけで、16の町と市はそれぞれ切り替え時スクリプトで自分のフラグを立てます。コトキタウンのものはsetflag FLAG_VISITED_OLDALE_TOWNです。13
ほかの作品も形は同じです。ファイアレッドのマップは1ページ22×15マスで、4ページ(カントーとナナシマの3つの組)があり、それぞれフィールドとダンジョンの2層を持ちます。カントーのフィールド層は38の区画で90マスを埋め、そらをとぶには3つ目のバッジが必要です。ファイアレッドの場所は、そのFLAG_WORLD_MAP_*フラグが立つと訪問済みとみなされます。各町の切り替え時スクリプトが入ったときにそのフラグを立て(setworldmapflag FLAG_WORLD_MAP_CELADON_CITY)、そらをとぶは訪問済みのマスしか受け付けません。23 クリスタルのマップは95のランドマークをピクセル位置で配置し、そらをとぶの行き先を24か所、ジョウトに12、カントーに12用意しています。町の行き先は入ったときのコールバックで設定され(VioletCityFlypointCallback: setflag ENGINE_FLYPOINT_VIOLET)、そらをとぶはENGINE_STORMBADGEを確認します。24 赤のタウンマップは、4ビットのグリッド上に屋外のエントリ37個(うち1つは未使用と記載)と、独自の位置を持つ屋内のエントリ60個を並べています。11の市のマップのどれかに入ると、wTownVisitedFlagのなかのその市のビットが立ちます。ソースのコメントは「mark town as visited (for flying)」(町を訪問済みにする、そらをとぶ用)で、そらをとぶのリストは未訪問の町を飛ばし、そらをとぶにはオレンジバッジと屋外のマップが必要です。22
4作品のどれも、最初から持ち歩ける地図をプレイヤーに与えてはいません。どれもプレイの途中で手渡します。赤とファイアレッドのタウンマップは、マサラタウンにいるライバルの姉からもらう道具です(赤では、プレイヤーがポケモン図鑑を持ってから差し出されます)。クリスタルのマップカードは、家の次の最初の町ヨシノシティでのもらいものです。エメラルドのポケナビは、家から数えて3つ目の町、カナズミシティのデボンの建物で手に入ります。442345127 壁の地図はもっと早く同じ画面を開きます。エメラルドは自宅の2階とすべてのポケモンセンターの1階に掛けており、ファイアレッドはポケモンセンター、トキワシティの学校、いくつかの家に掛けています。赤のHOUSEタイルセットは、マサラタウンのライバルの家に使われており、壁の地図のタイルを持っています。122344
まとめると、このルールは4作品、3世代にわたって一貫しています。プレイヤーが地図を手にすると、地図は訪れたかどうかに関係なく地方のすべての場所を描きます。例外はストーリーやイベントで伏せられた終盤の場所です。ファイアレッドのナナシマのページは、1のしまのポケモンセンターでスクリプトがフラグを立てるまで伏せられ、それらのページのなかでもへそのいわとたんじょうのしまは、プレイヤーが行くまで塗りつぶされています。エメラルドのバトルフロンティアとみなみのことうは、ランドマークのフラグが立つまで。クリスタルのカントーのマップは、プレイヤーがカントーに立つまで。44451223 ファストトラベルに並ぶのは、歩いて入ったことのある場所だけです。それは入ったときに立つフラグで記録され、屋外でしか使えず、中盤のバッジのあとでしか使えません。赤とファイアレッドでは3つ目、エメラルドでは6つ目です。13232422
4. ほかのモデル:Stardew Valley、どうぶつの森、夢をみる島
ポケモンは、町と町のあいだの土地に対するひとつの答えです。ほかの3作品は別の答えを出しており、その違いのひとつひとつが、Kiradexが下さなければならない選択です。この節の数値は各ゲームのコミュニティwikiから、夢をみる島については逆アセンブルから取ったものです。注にそう書いた箇所を除き、ゲームのコードと照合してはいません。29
Stardew Valley:カレンダーが開く、ハブとスポーク
Stardewはすべての端でフェードします。wikiの言葉では、「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.」(エリアの端に着くか建物に入って、移動中に画面が黒くフェードしたら、それはマップ間を移動している)。ワープはマップのプロパティで、wikiはその値を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」(つながっていない2つの区画からなる)で、牧場と山を結ぶ上の道と、バス停の道から入る下の区画があります。50 これらのページの場所一覧のボックスには、裏の森から魔女の沼まで、私の数えで26の場所が並んでいます。51
スポークは日付と行いで開きます。山は最初「only two exits: to the south leading to Pelican Town, and to the west leading to the Backwoods」(出口は2つだけ:南のペリカンタウンへ、西の裏の森へ)で始まります。鉱山は春の5日に開き、鉄道は夏の3日の地震のあとに、採石場の橋は工芸品の部屋のバンドルか25,000gで開きます。52 砂漠にはバスの修理が必要で、それには金庫のバンドルか40,000gがかかります。秘密の森には、鋼の斧以上で取り除く丸太があります。浜辺の潮だまりには木材300本の橋が必要です。53 wikiはプレイヤーの基本の速さを、歩き2、走り5、馬に乗って6.6としていますが、単位はなく、私はゲームのコードを開いて確かめてはいません。54
私の読みはこうです。ポケモンは、プレイヤーが持ち歩く能力、つまりバッジやひでんマシンでエリアに関門を設けます。Stardewは、コミュニティが成し遂げたこと、つまりバンドル、橋、あるいはある日付の地震で関門を設けます。後者は、共有のコレクションの町が、だれにもレベルのせいで締め出されたと感じさせずに使える種類のものです。
どうぶつの森:エーカーのグリッドと汽車
ゲームキューブの『どうぶつの森』(北米版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,」(プレイヤーがエーカーに入るたびに、ゲームの読み込み時に家から出る場合を除き、エーカーのデータで定められた位置に魚1匹と虫1匹が現れる)。そしてプレイヤーがそのエーカーから6マス離れると消えます。55 町の地図は早い段階で、アルバイト中にたぬきちから渡されます。地図は「is organized in a grid, with each square representing an acre,」(グリッドで構成され、各マスが1エーカーを表す)もので、海、川、建物、家を示しますが、木、アイテム、住民は示しません。56
汽車は、ゲームキューブ版でほかの町へ行く唯一の手段で、メモリーカードを介します。「The train ride takes a few minutes」(汽車の旅は数分かかる)。駅は「is located at the top of the player’s town,」(プレイヤーの町のいちばん上にある)、そして新しいゲームはプレイヤーがそこに着くところから始まります。57
私の読みはこうです。エーカーは町を読みやすくし、名前のついたマスの地図にします。そして1歩ごとのサイコロなしに、動き回ることに報いる出現のルールを与えます。汽車は、世界と世界のあいだの移動を、継ぎ目ではなくひとつの場面にします。
夢をみる島:画面ごとに切り分けた世界
『ゼルダの伝説 夢をみる島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. 技法を、数字つきのルールとして
測定が裏づけるルールを、それぞれの出どころとともに挙げます。ルールが測定された事実を推奨に変えている場合、その推奨は私のものであり、ルールの動詞がそれを示しています。
| 要素 | ルール | 出典 |
|---|---|---|
| ペース | 歩行1セルは16フレーム、約0.27秒。Kiradexの1タイルは0.25秒。すべての移動を、そのゲーム自身の歩きの秒数で見積もること。 | 赤、クリスタル、エメラルドのステップコード、GBATEK、PlazaRig.swift |
| 道路の長さ | 進行方向の軸に沿って画面2〜10枚ぶん。作品の最初の道路は2〜6枚。 | 測った16本の道路 |
| うねり | 横断する長いほうの歩きは道路の長辺の1.15〜1.70倍、帰り道は0.95〜1.42倍。道路の大きさは外枠ではなく道のりで決めること。 | 両端が徒歩でつながる9本の道路での、最短歩数と長辺の比 |
| 最初の区間 | ドアから次の町の主要な扉まで15〜25秒。1分の区間は道ではなくダンジョン。 | エメラルド58セル、ファイアレッド94セル。森か洞窟を通る250、267、314セル |
| 割合 | 面積で道は町の2〜4倍。マップ画面では5.9対1、町は1マスか2マスだから。 | クリスタル1.97、赤2.65、エメラルド3.70、ファイアレッド3.87、エメラルドのマップ |
| 密度 | エンカウントのある地面は最初の道路のマップの14%〜23%で、3本目と4本目には4%〜9%まで薄くなる。歩ける地面に対しては、最初の道路で19%〜38%。最初の道路にはトレーナーを置かない。 | 道路の表、歩けるセルに対する草の割合 |
| リズム | エンカウントのある地面では約9歩に1回、気づくものを。到着時には数歩の猶予を置く。下限と上り坂で、日照りと洪水を短く保つこと。 | エメラルドの4歩の猶予と、そのあとのrate 20、補正なしで11.1%。ファイアレッドのクールダウンと上乗せ |
| 帰り道 | 行きより短く、段差があり両端が徒歩でつながる9本の道路すべてで2%〜44%短い。帰りの草セルは0〜5で、行きの4〜19と対照的。段差は帰りのための一方通行の近道であって、行く手をふさぐ壁ではない。 | 9本の道路、草を最小にする探索 |
| 継ぎ目 | 2つのエリアを開いた継ぎ目で接させるのは、両方が同じ地面のセットで端を描く場所だけにすること。アートが変わる場所には2つのドアを持つ建物を置くこと。 | 赤の78本中76本、クリスタルの142本中138本、第3世代のプライマリセットが異なるもの134組中0組と120組中0組、異なる2つの場所を結ぶ赤のすべてのゲート |
| 隣の帯 | 隣のエリアを、端の向こうに少なくとも視界の半分ぶん描くこと。 | 15セルの画面に対する第3世代の7セル(東は8セル)、10セルに対する第1世代の6セル |
| 接続 | オフセットはふつうのこと。すべての接続はオフセットを反転させた逆向きを持ち、一方向の接続は意図的な描画上の工夫。 | エメラルドの134本中36本にオフセット、134本中134本が相互。ファイアレッドのヤマブキ |
| 地名カード | 入ったときに約3秒、場所の名前を示すこと。 | エメラルドの地名表示、約190フレーム |
| ゲート | ゲートはルールとごほうびが住む場所。節目の確認、警備員、数に達したときの贈り物。 | 赤のバッジの確認、のどの渇いた警備員、捕まえた10種、30種、50種での贈り物 |
| マップ画面 | 名前のついた長方形の粗いグリッド。ほとんどの場所は1マス、最大でも数マス。 | エメラルドの28×15、95の長方形のうち49が1マス、最大は4×3。どうぶつの森の5×6エーカー |
| ファストトラベル | プレイヤーが地図を手にしたら、訪れたかどうかに関係なくすべての場所を示す。ただしストーリーやイベントのフラグで伏せる少数を除く。ファストトラベルは行ったことのある場所だけを示し、それは入ったときのフラグで決まり、屋外からしか使えない。 | タウンマップ、マップカード、ポケナビ、壁の地図。赤のwTownVisitedFlag、クリスタルのそらをとぶの行き先、エメラルドのFLAG_VISITED_*、ファイアレッドのFLAG_WORLD_MAP_*。マップ画面との関係まで追っていない訪問記録として、夢をみる島のOW_ROOM_STATUS_VISITEDビット |
| 開放 | エリアは能力だけでなく、行いと日付でも開く。 | Stardewの鉱山、鉄道、採石場、砂漠、秘密の森。いあいぎりで267セルが156セルに |
| 遷移 | ひとつの屋外世界のなかは継ぎ目で。ドアと世界の端ではフェードで。 | ポケモンの継ぎ目、Stardewのフェード、夢をみる島の画面送り |
| 向き | 道路は端末の長軸に沿わせること。ひとつの視界に丸ごと収まる道路には、もう明かすものが残っていない。 | 10月3日のタイル数。エメラルドのRoute 101の20×20と、開いたDuoの29.7×20.9 |
表の出典:第1節のステップコードとフレームのタイミング12315、Kiradexの歩く速さ4、道路、移動、草、接続のスクリプト567188、エンカウントのコード3132、エメラルドのバッファ、越境、地名表示のコード91021、ゲートのスクリプト1920、マップ画面とプレイヤーがそれを手にする方法、そしてそらをとぶ1112132345244422、Stardew Valley、どうぶつの森、夢をみる島465253555825、このシリーズ最初の記事にある端末ごとのタイル数。60
このうち3つのルールには、もう一言添える価値があります。
継ぎ目のルールは、エンジンについてではなく、アートについてのルールとして述べています。ゲームボーイは隣の帯を現在のマップのブロックセットで描いたので、異なるタイルセットの隣をそもそも見せられませんでした。ゲームボーイアドバンスは越えるまで現在のマップのタイルセットで帯を描くので、私の読みでは、それが継ぎ目をひとつのプライマリセットに保ち、ほとんどをプライマリのメタタイルにとどめている理由です。38108 私はどちらもタイルメモリの制約だと読んでおり、アトラスを1枚だけ描くスマートフォンにはその制約はありません。残るのは視覚上の理由です。画面を横切る直線のところで素材が変わる道は、エンジンがそれを必要としたかどうかにかかわらず、継ぎ目に見えます。だからこのルールは、何もそれを強いないときでも、前半(地面が続くところでは開いたまま接する)と後半(アートが変わるところには建物を)を残しているのです。
ファストトラベルのルールは、そのまま写す価値がいちばん高いものです。ここで測ったポケモンのどの作品も、プレイの早い段階で地図を手渡し、訪れたかどうかに関係なくすべての場所を描き(ストーリーやイベントのフラグで伏せられる終盤の数か所を除く)、近道だけに関門を設けています。そしてどれも、近道を代金ではなく、どこかへ歩いたことによって得させています。44451213232224 XPが現実世界でスキャンしたカードからしか得られないコレクションアプリにとって、訪問フラグは正しい通貨です。かかるのは歩くことだけだからです。27
向きのルールは正典ではなくスマートフォンから来ています。縦向きのPro MaxはKiradexの縮尺で10.3×22.4タイル、開いたiPhone Duoは29.7×20.9タイルを見せます。したがって南北に走る道路は、ふつうのスマートフォンでその長さの22タイルを一度に見せ、カメラが中央に保つコレクターの前方に約11タイル。東西に走る道路は、開いたDuoでだけ30タイルを一度に見せ、前方に約15タイルです。602717 20×20のエメラルドのRoute 101は、開いたDuoのひとつの視界に丸ごと収まってしまいます。つまりそれほど短い道路は、そこではもう明かすものを何も持っていないということです。617
6. Appleのやり方:視界、継ぎ目、ルーム、そしてマップ
Kiradex Worldの下にあるエンジンは、最初の記事が示したものです。2Dレンダラーとして使うRealityKitのシーン、1テクセルあたり整数のデバイスピクセルで構える正射影カメラ、1回の描画呼び出しで描く1つのMeshDescriptorメッシュとしての地面、不透明度のしきい値を持つUnlitMaterialのマテリアル、そして無効にしたRealityViewのモーションブラーとトーンマッピング。60 建物の記事は、そこに2つ目のメッシュで奥行き順に並べたオブジェクト、データとしてのワープ、そしてステージに新しいアイデンティティ.id(floor.name)を与えて階をその場で入れ替えるしくみを加えました。後者によって、SwiftUIは一方のRealityViewを破棄して次を組み立てます。37 柵の向こうのエリアには、このエンジンからさらに3つのものが必要です。継ぎ目の向こうの隣のエリアの眺め、切れ目なしにサーバー上でルームを替える方法、そしてマップ画面です。そのどれもまだ作っておらず、この節のことは何ひとつスマートフォンで測っていません。これはブリーフの土台となる計画であり、コストはそれぞれ名前を挙げ、未測定と記しています。
スマートフォンに見えるもの
タイル数は最初の記事の表から取っています。Appleの仕様ページとXcode 27のシミュレータのプロファイルから、Kiradexの整数倍率で計算したものです。60
| 端末と向き | 1テクセルあたりのピクセル | 見えるタイル(横×縦) | 視界の半分 |
|---|---|---|---|
| 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倍に縮小されるので、実機でも同じ数のタイルがパネルを満たすはずです。1テクセルあたり約5.6パネルピクセルで、コンポジタが最初の記事の想定どおりに縮小すればの話です。これは実機では未検証で、最初の記事の最初の手順は、実機でnativeScaleをログに出すことです。6017 ヒューマンインターフェイスガイドラインは、ゲームが「look good and behave well at various aspect ratios」(さまざまなアスペクト比で見栄えよく、正しく動作する)ことを求めており、最初の記事はそれを、帯ではなくより多くの世界を見せるための論拠と読みました。広場がやっているのはそれです。6260
エリアについては2つのことが導かれます。カメラがコレクターを追う場合、前方の眺めは視界の約半分です。27 南北に走る道路は、どのスマートフォンでもよく見える道路です。縦向きのPro Maxでは22タイルを一度に見せ、前方に約11タイル、開いたDuoでは21タイルを一度に見せ、前方に約10タイル。東西に走る道路は、開いたDuoでは30タイルを一度に見せ前方に約15タイルですが、縦向きのPro Maxでは10タイルしか見せず前方に約5タイルなので、目的地が近い場所に向いています。6017 だからブリーフの長い歩き、草原の小道は南北に走っているのです。そして最も強く東西に伸びるエリアであるバインダー通り(44×14、横幅が高さの3倍以上)は、開いたDuoならどこに立ってもほとんどを見渡せる店先の並ぶ通りになっています。湖畔(36×20)とギャラリー地区(30×20)も横長ですが、ブリーフのなかでは立ち止まる場所、つまり岸辺と美術館の地区であって、どこかへ向かう歩きではありません。2617
RealityKitでの継ぎ目
建物の記事の階の入れ替えは、継ぎ目には向かない道具です。一方のRealityViewを破棄して次を組み立てるには、それを隠すフェードが必要ですが、アプリのドアにはまだフェードがありません。現在は、ドアへ一歩踏み込んでから220ミリ秒後に場所が変わり、階の変更はフェードなしでステージを入れ替えます。このシリーズのモーションの記事は、その両方を覆うベールを提案しています。継ぎ目には、定義上フェードがありません。376316 そこで継ぎ目の計画では、シーンをひとつに保ちます。コレクターが、接続を持つ端から視界の半分以内に近づくと、ステージは隣のエリアの地面を2つ目のメッシュとして、1つ目と同じ種類のMeshDescriptorから組み立て、ワールド単位で接続のオフセットの位置に置き、隣のエリアのオブジェクトをそれぞれの奥行きに加えます。コレクターの足が端を越えると、ステージは基準を移します。隣のエリアが現在のエリアになり、古いエリアは背後の帯になります。そしてカメラは、現在はマップの範囲内に制限してプレイヤーを追っていますが、両方が読み込まれているあいだはその和集合の範囲内に制限されます。2726
机上でこれを安くする、エンジンの事実が3つあります。地面はエリアごとに1つのメッシュと1回の描画呼び出しなので、隣のエリアが加えるのは地面の描画呼び出し1回とオブジェクトの1回です。6037 すべてのピクセルは切り抜きで深度を書き込むので、隣のエリアの木は現在のエリアと同じ深度の規則でコレクターと前後が決まり、新たな並べ替えは要りません。37 そしてフォージはすでにエリア全体を、文字、オートタイルされた地面、オブジェクト、ワープとして書き出しているので、隣のエリアは同じ種類の2つ目のファイルです。ブリーフはそこにconnectionsリストを加えます。1426 これらのどれからもわからないのは、2つ目のメッシュを必要になった瞬間に組み立てるコスト、そして1フレームのうちに組み立てるとカクつきが起きるかどうかです。それは未測定です。そのためブリーフのチェック6は2つの部分からなり、どちらも隣のメッシュを組み立てる前から越境の終わりまで、接近全体をカバーします。メインスレッドの停滞を捉えるフレームごとのタイミングログと、黒いフレームを捉える、キャプチャしたすべてのフレームの検査です。抜き取りのチェックでは足りません。毎秒60枚のうちの1枚の黒いフレームは、コールバックのタイミングを乱すとは限りませんし、100ミリ秒ごとの抜き取りでは60ヘルツで6フレームに1枚しか見ません。17 タイミングの部分と全フレームの規則は、明るさを抜き取りで調べていたドシエのチェックに私が加えたものです。
オートタイルは、GBAのルールが扱っていない唯一のものです。第3世代が継ぎ目を共有の地面に保ったのは、隣の帯が現在のマップのタイルで描かれたからです。108 Kiradexはすべてのエリアを1つのアトラスのパレットから描くので、その制約は当てはまりません。しかしエリアの端のブロブ型オートタイルは、そのエリア自身の文字から計算されます。フォージが継ぎ目の向こうを見なければ、継ぎ目を越える道は両側で縁取りになって途切れてしまいます。そこでブリーフでは、フォージがすべての接続をまたいで端のマスクを計算します。26
ルーム、プレゼンス、再接続
Kiradexの広場はサーバーのルームです。最大約40人のプレイヤーが入るルームを地域ごとにシャーディングし、FastAPIとWebSocketsの上で動かしています。27 柵の向こうのエリアは自然にもうひとつのルームになり、そこからシングルプレイヤーの携帯機が抱えたことのない問題が生まれます。継ぎ目の向こうにいる人々です。計画では、クライアントは隣のルームの帯を描き始めたときにそのルームの歩く人々を購読し、中央広場の端からバインダー通りの人々が見えるようにします。そして越えた瞬間に自分のルームを切り替え、歩く人が止まることはありません。26 ドアと路面電車にはフェード、モーションの記事のブリーフがドアに加えるベールを使い、そのフェードが再接続を覆います。建物のドシエが室内についてすでに提案していたとおりです。1626 最初の記事の、黒い画面に対する対処はこのフェードに当てはまります。RealityViewを保持するSwiftUIビューの不透明度をアニメーションさせると描画されないままになったので、フェードはその上に描くベールにします。60
サーバーには、クライアントが描くのと同じマップが必要です。現在、server/app/plaza.jsonは町の文字を持ち、サーバーが歩きを検証できるようにしています。ブリーフでは、各エリアのコピーが文字と接続を持ち、継ぎ目を越える歩きは継ぎ目の両側で検証されます。6026 実際のネットワーク上でのルームの切り替えのコスト、そして2つ目のルームの購読が継ぎ目の近くで広場のメッセージ量を倍にするかどうかは、未測定です。
SwiftUIでの地名カード、マップ、路面電車
エリアの名前はピクセルのレイヤーではなくSwiftUIに属します。最初の記事は、5テクセルのピクセルフォントがKiradexの倍率では13.3ポイントか10ポイントになり、後者はヒューマンインターフェイスガイドラインの最小11ポイントを下回ることを見つけ、会話のテキストをUIの倍率のSwiftUIに移しました。地名カードも同じ種類のテキストです。60 そのタイミングはエメラルドから取ります。画面上に約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」(私たちのサーバーが保持するのは公開プロフィールカードと経済だけ)とあります。私はそこに訪問済みの集合をもうひとつのフィールドとして加えたいと考えています。コレクターが入ったことのある5つのエリアがどれかを示すリストに限り、位置も、テキストも、訪問時刻も持たせず、ほかと同じくGame CenterのプレイヤーIDをキーにします。計画が求めるプライバシー面の検討は、これも対象に含めなければならないでしょう。2726
コスト、そして未測定のもの
この節のことは何ひとつ時間を計っていません。未測定のコストは次のとおりです。コレクターが端に近づいた瞬間に隣のエリアの地面とオブジェクトのメッシュを組み立てること、両方が読み込まれているあいだ2つのエリアのメッシュを描くこと、継ぎ目の近くで2つ目のルームを購読すること、そして越えるときのルームの切り替え。それらをどう測るかは、最初の記事のキャプチャのルールが決めます。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ヘルツでまっすぐの1タイルを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. 5つのエリア:中央広場と、その先の4つ
| エリア | どんな場所か | 大きさ(タイル) | 接続先 | コレクションのループでの役割 |
|---|---|---|---|---|
| 中央広場(既存) | 町:家、ホール、キオスク、噴水のテラス、到着の中庭 | 40×30 | ハブ | 到着し、お気に入りのカードを見せびらかし、部屋やホールに入る |
| バインダー通り | 商店街:建物のキットのカードショップ、交換所、求めるものの掲示板、のちに6つの市場の屋台の列 | 44×14 | 中央広場の東、開いた継ぎ目 | コインをコスメティックに使う。町のコレクターたちが見せてほしいと求めているものを見る。交換画面。その段階が来たらマーケットプレイスの屋台 |
| 草原の小道 | 草原と雑木林を抜ける公園の道。見つけものが現れる花畑と、湖の側からしか開かない門のある生け垣の帰り道 | 24×60、長軸は南北 | 中央広場の北、開いた継ぎ目 | 見つけもの(項目6)、友だちとの散歩、湖への道 |
| 湖畔 | 小道の終点:岸辺、桟橋、ベンチ、ボートハウス | 36×20 | 草原の小道の北、開いた継ぎ目 | 夕暮れに座ってカードを見せる静かな場所。週ごとの集まりの場 |
| ギャラリー地区 | 石造りの地区:美術館と、コレクターたちの展示のギャラリー | 30×20、加えて8×6のアーチの建物 | 中央広場の西、アーチ経由(2つのドア) | サーバー全体で完成したセットが美術館を満たす。アーチにいる節目の管理人(項目7) |
中央広場の先の総面積は616+1,440+720+600で3,376タイル、中央広場の1,200の2.8倍で、正典の1.97〜3.87の帯に収まります(第5節、割合)。1733 ギャラリー地区が建物の向こうにあるのは、異なる地面のセットの石で描かれるからです(第5節、継ぎ目)。ほかの3つは中央広場の芝生と舗装を共有しているので、開いた継ぎ目で接します。全部で3つ、中央広場の東の端にバインダー通り、北の端に草原の小道、そして草原の小道の北の端に湖畔です。26 バインダー通りの求めるものの掲示板は、町のコレクターたちが見せてほしいと求めているものを、すでにそれを判定しているコード(Kiradex/World/Wants.swift)で実際のカードと照らして示します。屋台はマーケットプレイスを待ちます。ワールドの計画では、マーケットプレイスは後の段階でeBayを通します。6527
提案するエリアを、マップ画面のグリッドに合わせて描いたもの。模式図にすぎない。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回 | 約1秒と再接続 | ファストトラベル、遷移 |
草原の小道の60タイルの長さは、うねって78〜90タイルの道のりになり、係数は1.3〜1.5です(第5節、うねり)。26 道だけでは帰り道を短くできません。すべての一歩が双方向に歩けるグリッドでは、到着から桟橋への最短の歩きは、そのまま帰りの最短の歩きでもあり、もっとまっすぐな道があれば行きにもそれが使われるからです。短縮には一方通行の何かが必要です。ここではそれが生け垣の門です。幅2タイルの生け垣の小径が、草原の小道の東側を桟橋と一直線にまっすぐ下り、中央広場の北の端の、ホールとその東の家のあいだに出ます。そこから両者のあいだの芝生が到着の中庭へと下っていきます。小径の湖側の端にある門は、湖の側からしか開きません。行きは閉じたままで道はうねり、帰りは開いて小径はまっすぐです。それが正典の一方通行の帰りの近道(第5節、帰り道)を平らに置いたものです。3つのエリアを項目3の共有の8方向グラフでモデル化しました。町はフォージが現在描くとおりに、小径と桟橋は上のとおりに配置しています。私は、草原を横切る4本の生け垣、12行ごとに1本、それぞれに幅2タイルの切れ目を持つものでうねらせることにしました。斜めの一歩はどのつづら折りも短く切り詰めます。どの切れ目の位置でも、等間隔の2本の生け垣では、このグラフ上で草原を78タイルうねらせることはできません。端から端まで最大66.46タイルにしかなりません。等間隔の3本ならできますが、ぎりぎりです。8,000通りの切れ目の位置のうち6通りが78〜79.77タイルのうねりになり、その6通りのうち5通りは行きも110〜120タイルの帯に収まり、114.05〜119.02タイルで、帰り道は行きの0.740〜0.772と、0.8の目標を下回ります。4本の生け垣なら、160,000通りの位置のうち5,912通りで78〜90タイルのうねりになり、フォージが草原を配置する余地が残ります。4本にした理由はこの余裕であって、グラフがそれを強いているわけではありません。それら4本のレイアウトでは、帰り道は88.07タイル、行きは108.74〜133.75タイルです。0.8の目標には少なくとも行き110.09タイルが必要で、110〜120タイルの行きの帯のなかでは4,111通りのレイアウトすべてがそれを満たし、0.73〜0.80です。門を双方向に開けると、2つの歩きは等しくなります。66 以前のモデルの2本の生け垣でもう足りなくなったのは、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で、通り抜ける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節)。したがって花畑は後の道路と同じ水準で、どの最初の道路よりも下です。きらめきは置かれて目に見えるので、花畑はそれを縁取るだけでよく、1歩ごとの判定を担う必要はないのです。17
- どう現れるか。 1歩ごとのサイコロではありません。草原の小道に入ると、サーバーはそのコレクターのために、花畑のなかに目に見えるきらめきを最大1つ置きます。コレクター、日付、エリアから決定的に選び、どうぶつの森のエーカーに入ったときの出現ルールに倣います。これはそのコレクターがその日に3つ受け取るまで続きます。5526 目に見えるきらめきは、子どもにもルールをわかりやすく保ち、第5節のリズムの行にあるクールダウンと上り坂を必要とせずに連続や偏りを避けます。
- 何であるか。 世界の側のものだけです。部屋に飾るステッカーやフレーム、スリーブやピンのコスメティック、あるいはその日のクエストのひとつを名指すメモで、そのクエストは本物のスキャンでしか完了できません。クエストはすでにコレクションそのものから判定されています(
Kiradex/World/Quests.swift)。2765 カードには決してならず、XPにも、売り物にもなりません。見つけものが何かを買う理由になることは決してありません。コインは保留です。ワールドの計画では毎日の訪問でコインを得られますが、その量や上限は定めておらず、コインを第4段階に置いています。そのためコインの見つけものは、そのルールができるまで先送りし、できたときには上乗せではなく、同じ毎日の訪問の予算から出します。27 - だれに見えるか。 各コレクターのきらめきはその人のものです。一緒に歩く友だちには、それぞれ自分のものが見えます。奪い合うものも、争うものもありません。
チェック: 10(見つけもの)。
7. アーチとその管理人
中央広場とギャラリー地区のあいだの建物は、両側にドアがあり、カウンターに管理人のいる8×6の部屋です。管理人は、コレクターの登録済みカードの枚数が初めて10、30、50、100を超えたときにコスメティックを手渡します。第5節のゲートの行にあるコレクションの節目の関門で、XPと同じく現実世界のコレクションから数えます。2026 この部屋は、アートが芝生から石へ変わる場所でもあります(第5節、継ぎ目)。何も閉ざされていません。アーチは常に開いており、管理人はただ与えるだけです。
チェック: 11(アーチの管理人)。
8. マップ画面
1マス10タイルを丸めた、名前のついた長方形の16×12のグリッドです。中央広場が4×3、その東にバインダー通りが4×1、その上に草原の小道が2×6、いちばん上に湖畔が4×2、西にギャラリー地区が3×2。湖畔、草原の小道、中央広場を積み重ねると、12行のうち11行を占めます(第5節、マップ画面)。2617 すべてのエリアは初日から描かれ、名前がついています。これは正典ではなくKiradex自身の選択です。4作品は、地図を手にしたあとは終盤の数か所を除いてすべての場所を描きますが、地図そのものはプレイの途中で手渡します(第5節、ファストトラベル)。コレクションの町には、それを見る権利をだれかに稼がせる理由がありません。現在のエリアは脈打つように光り、訪問済みのエリアには路面電車の停留所が表示されます。開いたDuoではマップは世界の横にパネルとして置き、スマートフォンではシートにします。27
チェック: 8(マップ画面のモデル)。
9. 路面電車
屋外のエリアにはそれぞれ停留所があります。停留所は、コレクターがそのエリアに初めて入ったときに開きます。第5節のファストトラベルの行にある訪問フラグで、入ったときに立ち、レベルや支払いで立つことは決してありません。1326 マップ画面で訪問済みのエリアをタップすると、そこへ乗っていきます。フェードアウトし、ルームが替わり、そのエリアの停留所でフェードインし、それから地名カード。屋内からの乗車はありません。そらをとぶが屋内から使えないのと同じです(第5節、ファストトラベル)。13 路面電車は、湖畔までの28〜30秒の歩きを、一度歩いたあとはワンタップに変えます。能力ではなく訪問によって得る近道です(第5節、開放)。26
チェック: 9(路面電車のルール)。
10. 名前とアート
すべてのエリアの名前、看板、文字列は保護された名前の拒否リストを通過し、すべてのタイルとスプライトはフォージから生まれます。2726 拒否リストはまだ存在しません。ドシエはリポジトリにそれを置くと約束していましたが、リポジトリにはありません。それを作ることもこのブリーフの一部です。保護された名前を1行に1つずつ並べた素朴なリストを、フォージの横に置いてリポジトリにチェックインし、フォージの書き出しからすべてのエリアの名前、看板、文字列を読み取り、リストのどれかが大文字小文字を区別せずに見つかれば失敗するテストを添えます。26 番号つきの道の名前は使わず、「地方」の命名体系も使わず、正典のゲートの見た目を再現する建物も作りません。大きさとルールは一致してかまいませんが、形と名前はKiradex自身のものでなければなりません。26
チェック: 13(名前とアート)。
11. 作業の順序
ワールドの計画は、広場(ルーム、同期、吹き出し、プロフィール、交換画面)を3番目に、コインとショップを4番目に置いています。27 エリアは段階3bとして、広場のネットワークが安定したあと、コインの前かそれと並行して収まります。26
- フォージとサーバーでの接続(形式、相互性、継ぎ目の描画、ルームの切り替え)、サーバーの8方向の探索、そして拒否リストとそのテスト。最初のエリアはバインダー通りです。建物の作業ですでに設計したカードショップを使い、いちばん小さいからです。
- 草原の小道と見つけもの(サーバーでの配置、1日の上限、中身)。
- マップ画面と路面電車。
- 湖畔。
- 美術館の内部ができた時点で、アーチを含むギャラリー地区。バインダー通りの屋台の列は、マーケットプレイスの段階を待ちます。
ワールドの計画がすべての段階に求めるとおり、各ステップはTestFlightのビルドで、そのチェックのためのキャプチャを添えます。27
受け入れチェック
どれも、フォージの書き出しとサーバーのテストに対するスクリプトか、シミュレータでのキャプチャで実行できます。チェック6は、シミュレータでのキャプチャ1回を除き、実機で実行します。26
- 相互性。 書き出しには開いた継ぎ目がちょうど3つあります。中央広場の東とバインダー通り、中央広場の北と草原の小道、草原の小道の北と湖畔です。そしてすべての接続
(a, dir, b, off)について、書き出しは(b, opposite(dir), a, −off)を持ちます。テストは一方向の接続がひとつでもあれば例外なく失敗します。 - 越境点。 各エリアの到着地点とドアからの幅優先探索で、すべての継ぎ目の両側に、向こう側の歩けるタイルに面した越境タイルが少なくとも2つずつ見つかること。
measure_gen3_routes.pyの方法です。6 - 距離。 項目3の共有の8方向探索を、結合したエリアの上で、生け垣の門を一方通行の辺として(湖の側からまっすぐの一歩でだけ入れ、湖へ向かって出ることは決してできない)、すべての長さを斜めの一歩を√2と数える経路コストとして実行し、到着地点からカードショップまで最大60タイル、到着地点から湖畔の桟橋まで110〜120タイル、桟橋から到着地点まで行きの歩きの0.8倍以下、到着地点から美術館のドアまで最大70タイルと報告すること。フォージは毎秒4タイルでの時間を出力します。
- 割合。 中央広場の先のタイル数を中央広場のタイル数で割った値が2.0〜3.9にあること。
- 向き。 草原の小道の高さが幅を上回ること。
- 継ぎ目で黒いフレームもメインスレッドの停滞もないこと。 実機のビルドで、コレクターは中央広場とバインダー通りのあいだの継ぎ目を歩いて越えます。ステージがバインダー通りのメッシュを組み立て始める前、継ぎ目から視界の半分以上手前のタイルから出発し、継ぎ目を越えた最初の一歩が終わって中央広場が背後の帯になるまで歩きます。その全区間を2つの記録でカバーします。この実行では、ProMotionディスプレイの可変のリフレッシュレートが歩きの途中でカウントを動かさないよう、ディスプレイリンクが
preferredFrameRateRangeで60ヘルツを要求します。Appleはこの範囲を、ディスプレイリンクができるかぎり守ろうとするものとして説明しているので、実際に保たれたレートを示すのは要求ではなくタイミングログです。67 1つ目の記録は、ディスプレイが表示するすべてのフレームです。そのレートでの録画で残し、1フレームずつ検査します。フレームの平均輝度が区間の中央値のフレームの4分の1未満であれば黒いフレームとし(しきい値は私が決めたもの)、区間のどこかに黒いフレームが1枚でもあればチェックは失敗です。区間内の録画のフレーム数は、同じ区間のタイミングログのコールバック数と一致しなければなりません。フレームを落とすキャプチャが、黒いフレームを見逃すことで合格してしまわないようにするためです。表示されたすべてのフレームを記録できると示されたキャプチャ方法はまだなく、この一致が、ある方法がそれをできるかどうかを決めます。数が食い違い、タイミングログが後述の自身の規則に合格している場合は、キャプチャの欠陥であり、その実行は数に入れません。数が食い違い、タイミングログがその規則に不合格の場合は、チェックが失敗です。2つ目の記録は、Apple自身の例が登録しているのと同じくメインのランループに登録したCADisplayLinkのコールバックのtargetTimestampで、Appleのドキュメントによれば次のフレームが表示される時刻です。これを毎フレームログに出します。連続する値の間隔は、どれも25ミリ秒、60ヘルツで1.5フレームを超えてはなりません。こうすれば、黒いフレーム1枚と同じく、落ちたフレーム1枚でもチェックは失敗し、越えるときだけでなく隣のエリアを組み立てているあいだのメインスレッドの停滞も捉えられます。タイミングログが60ヘルツ以外のレートに落ち着いた実行は数に入れず、この実行では低電力モードをオフにします。Appleは、レートを変えうるもののなかに、そのモード、危機的な温度状態、アクセシビリティの設定を挙げているからです。67 端末は、手もとに来れば開いたiPhone Duoです。この記事を書いている時点で私のMacにペアリングされたiPhone Duoはないので、それまでは同じ継ぎ目でiPhone 18 Pro Maxを使ってチェックを実行します。それでわかるのは、スマートフォンで接近と越境が停滞したり画面が消えたりするかどうかであり、Duoの内側ディスプレイがどうフレームを刻むかではありません。シミュレータは代わりになりません。私の読みでは、シミュレータのフレームタイミングが測るのは、それを動かしているMacであってスマートフォンではないからです。これとは別に、開いたDuoのシミュレータでテストバンドルの内部からキャプチャし、コレクターが継ぎ目の手前の中央広場の最後のタイルにいるとき、バインダー通りが少なくとも14タイル見えること。6064 - 地名カード。 継ぎ目の越境か路面電車の到着のあと、カードが2.5〜3.5秒のあいだ画面上にあること。
- マップ画面のモデル。 ユニットテスト:すべてのエリアの長方形が16×12の内側にあり、2つが重ならず、すべてのエリアに名前があり、現在のエリアに印がつき、未訪問のエリアの停留所は無効になっていること。
- 路面電車のルール。 サーバーのテスト:未訪問のエリアへの乗車は拒否される。屋内からの乗車は拒否される。乗車は行き先の停留所で終わる。
- 見つけもの。 サーバーのテスト:エリアに入るごとにきらめきは最大1つ、コレクター1人につき1日最大3つ、同じコレクター、日付、エリアなら同じきらめき、そして中身はコスメティックとクエストのメモの表からだけ引き、カード、XP、コインには決してならない。フォージのテスト:花畑が草原の小道の歩けるタイルの12%〜18%を覆う。
- アーチの管理人。 ユニットテスト:4つの節目の贈り物が、登録枚数10、30、50、100でそれぞれ1回ずつ発生し、コインや購入からは決して発生しない。
- サーバーとの一致。 サーバーがすべてのエリアの文字と接続を読み込み、項目3の8方向探索で、コレクターを到着地点から2つの継ぎ目を越えて湖畔の桟橋まで歩かせ、生け垣の門を通って戻らせること。アプリとサーバーはどちらの方向でも同じタイルと同じコストを返し、クライアントの探索が拒む一歩(角を切る一歩や、小径から門を通って外へ出る一歩)はサーバーも拒む。既存のサーバーテストのパターンです。3728
- 名前とアート。 拒否リストがテストとともにリポジトリに存在し、テストが合格すること。すべてのエリアの名前、看板、文字列がリストを通過し、すべてのタイルとスプライトがフォージから生まれていること。
このブリーフに含めないもの
- 1歩ごとのランダムエンカウント、あるいは野生のバトルのように遊べるものすべて。見つけものは置かれ、目に見えます。
- 中心となるエリアへの能力による関門。 どのエリアもレベル、ピン、購入、道具では開きません。エリアは歩いて行けば開き、稼ぐのは近道、つまり路面電車だけで、それも訪問によって稼ぎます。第5節の開放の行を、優しいほうに読んだものです。5226
- 人が集まる2つの場所のあいだの、約30秒を超える移動で、路面電車がないもの。正典の1分の区間はダンジョンです。7
- 段差、一方通行の段差を持つ段丘、セル単位の高さ。 高さの記事に先送りし、そこで決めます。それまでブリーフは、一方通行だが平らな生け垣の門から帰り道の短縮を得ます。36
- 番号つきの道の名前、「地方」の命名体系、バッジで関門を設けたファストトラベル、正典のゲートの見た目を写した建物。27
- 一方向の接続。 正典はそれを描画上の工夫として使いますが、このブリーフには一つもなく、チェック1はそれがあれば失敗します。8
- コインの見つけもの。ワールドの計画が毎日の訪問で得られるコインの量を定めるまで。27
- マーケットプレイスの段階より前の、バインダー通りのマーケットプレイスの屋台。27
重要なポイント
アートを描く人へ
- 継ぎ目は地面が続くところにだけ描くこと。赤は78の接続のうち76で同じタイルセットをつないでおり、異なる2つの場所を結ぶ赤のゲートは、どれもタイルセットが変わる場所にあります。2つのドアを持つ建物が、素材を変える誠実な方法です。8
- 最初の道路は短く、くさむらをいちばん多くすること。画面2〜6枚ぶん、マップの14%〜23%をエンカウントのある地面にし、トレーナーは置かない。旅が進むにつれて薄くしていきます。56
- マップ画面は、名前のついた長方形の粗いグリッドとして描くこと。エメラルドのものは28×15マスで、95の長方形のうち49が1マスです。11
エンジンを作る人へ
- 接続は方向、隣、オフセットを持つデータとして保存し、すべての接続にオフセットを反転させた逆向きがあることをテストすること。エメラルドの134本はすべてそうなっています。842
- 隣のエリアを端の向こうに少なくとも視界の半分描くこと。第3世代はプレイヤーが左右それぞれ7セル見えるので7セル(東は8セル)をコピーします。Kiradexの倍率では、開いたDuoで15タイル、縦向きのPro Maxで12タイルです。960
- 継ぎ目ではシーンをひとつに保ち、シーンの入れ替えは、フェードがそれを隠すドアとファストトラベルのためにとっておくこと。1037
- 距離は定規ではなく探索で、エンジンが持つすべての移動規則を込めて測ること。両端が徒歩でつながる測定済みの9本の道路では、横断する長いほうの歩きは長辺の1.15〜1.70倍、帰り道は0.95〜1.42倍で、帰りは行きより4分の1短くなることもあります。クリスタルの片側の壁と横向きの角のジャンプを入れない探索では、Route 32は両方向とも110セルですが、入れると行き132セル、帰り128セルです。5617
- アプリとサーバーに、ひとつの歩行グラフを持たせること。クライアントが8方向、サーバーが4方向で歩くなら、テストが測る距離はどれも、その一方にしか当てはまりません。28
ループを設計する人へ
- すべての移動を秒で見積もること。正典では最初の区間は徒歩15〜25秒で、1分はダンジョンです。7
- 帰り道は行きより短くし、そのための一方通行の何かを与えること。双方向に歩けるグリッドでは、最短の帰りは最短の行きと同じだからです。正典は段差でそれを行い、最大44%短くします。向こう側からしか開かない門なら、高さなしでそれができます。5666
- プレイヤーが地図を手にしたら、すべての場所をそこに示し、稼がせるのは訪問による近道だけにすること。ここで測ったポケモンのどの作品も、プレイの途中で地図を手渡し、訪れたかどうかに関係なくすべての場所を描き(ストーリーやイベントのフラグで伏せられる終盤の数か所を除く)、入ったときに訪問フラグを立て、ファストトラベルには訪問済みの場所だけを並べます。Kiradexはさらに一歩進んで、初日から地図を見せます。4445121323222426
- エリアはレベルや購入ではなく、Stardewのように行いと日付で開くこと。そして歩く人に、どこへ行ってもコレクションでできることを与えること。5227
よくある質問
見下ろし型RPGの道路はどれくらいの長さにすべきですか?
2Dのポケモン作品では、進行方向の軸に沿ってゲーム機の画面2〜10枚ぶん、最初の道路は2〜6枚ぶんです。セルで数えると、私が測った16本の道路の長辺は20〜108セルです。端から端まで歩ける9本では、道がうねるため、長いほうの方向の最短の横断はその長さの1.15〜1.70倍、帰り道は0.95〜1.42倍です。1セル16フレームで、ドアから次の町の主要な建物までの最初の区間は、エメラルドで15.5秒、ファイアレッドで25.2秒かかります。56717
ポケモンはロード画面なしでどうやってマップをつないでいるのですか?
各マップは隣のマップを方向とオフセットとともに列挙しています。エメラルドでは、エンジンが現在のマップを7セル(東は8セル)の余白を持つバッファにコピーし(「the player has 7 metatiles of view horizontally in either direction」、プレイヤーの視界は左右それぞれ7メタタイル)、接続のある側の余白を隣のマップの7行または7列(東は8列)で埋め、現在のマップのタイルで描きます。プレイヤーが越えると、新しいマップのセカンダリタイルセット、パレット、音楽、天気を読み込み、地名の表示をスライドさせます。フェードはありません。赤も、3ブロック、6セルの余白で同じことをしています。91039
カントーの道路にはなぜゲートがあるのですか?
データについての私の読みでは、ゲームボーイの継ぎ目は同じタイルセットで描かれた2つのマップしかつなげず、ゲートはタイルセットが変わる場所の扉だからです。赤の78の接続のうち76は同じタイルセットをつなぎ、異なる2つの場所を結ぶ赤のゲートは、どれも2つのタイルセットをつないでいます。ゲートはルールも抱えています。飲み物をほしがるヤマブキの警備員、Route 22でのバッジの確認、そして捕まえた10種、30種、50種で道具をくれる3人の助手です。タイルセットという理由を裏づける開発者の発言はありません。8192029
ポケモンの段差はなぜ一方通行なのですか?
段差のセルの挙動が進む方向をひとつ指定しており、プレイヤーはその方向にしか越えられません。初期の道路で測ると、段差は手前の町を向いています。段差があり両端が徒歩でつながる9本の道路すべてで、帰りは行きより2%〜44%短くなります。それを探索した4本の道路では、帰り道が通るくさむらは0〜5セルで、行きの4〜19セルと対照的です。365618
そらをとぶは、飛べる町をどうやって決めているのですか?
町に入ったときに立つ訪問フラグです。エメラルドでは16の町と市がそれぞれ切り替え時スクリプトでFLAG_VISITED_*フラグを立て、地方マップは、そのフラグが立っているときだけ町をそらをとぶの行き先として示します。赤はwTownVisitedFlagに市ごとのビットを持ち、クリスタルはマップのコールバックでそらをとぶの行き先を設定します。そらをとぶにはバッジ(赤とファイアレッドでは3つ目、エメラルドでは6つ目)と屋外のマップも必要です。13222423
町は道と比べてどれくらいの大きさですか?
2〜4分の1の大きさです。道路のセル数を町のセル数で割ると、クリスタルで1.97、赤で2.65、エメラルドの陸の道路で3.70、ファイアレッドで3.87です。エメラルドのマップ画面では比が5.9対1になります。町は大きさにかかわらず1マスか2マスしか取らないからです。3334
ポケモンの道路の作り方を真似するのは合法ですか?
仕組み、大きさ、手法は著作権で保護されません。個々のタイルやスプライトは著作権で、名前とマークは商標で保護されます。このシリーズの最初の記事がその線引きを扱っており、システムや操作方法を著作権の対象外とする米国著作権局のCircular 33と、Palworldの開発元に対する任天堂の訴訟にある特許を取り上げています。60 このブリーフは数値とルールを借り、すべてのタイルをKiradex自身のフォージから描き、名前は拒否リストと照合しています。26
この記事の作り方について。 背景となる調査ドシエは2026年10月4日に、pretの逆コンパイルのシャロークローンから、出力とともに保存した6本のPythonスクリプトで測り、さらにStardew Valley Wiki、Nookipedia、zladxの逆アセンブル、Porymapのマニュアル、GBATEK、Pan Docs、Bulbapediaの1ページ、Appleのページを保存したものからまとめました。本文中のポケモンの数値はすべてスクリプトの出力で、各注がそのスクリプトを示しています。公開前の10月5日の2回目のレビューで、3つの再測定(クリスタルの片側の壁と角のジャンプ、段差を越える走り、アプリの8方向の歩きでのブリーフの草原)と、エンカウントのコードの猶予の歩数のより丁寧な読み直しを行いました。何が動いたかは各注に記しています。第7節の提案は私のものであり、そう明記しています。そのどれもまだ作っていません。
このサイトの関連記事:iPhoneでつくるピクセルアートの世界はこのシリーズの最初の記事で、タイルシステム、RealityKitのレシピ、そして本記事の視界の土台となる端末ごとのタイル数を扱っています。ピクセルアートの人物:iPhoneでのキャラクターとクリエイターは、これらの道路を歩くコレクターです。ピクセルアートの建物:iPhoneでの家、ホール、室内には、路面電車とアーチが再利用するドア、ワープ、階の入れ替えがあり、本記事が高さの記事に委ねた段差の拒否もあります。開発者のためのiPhone Duoは、視界の半分の帯の計算の元になる内側ディスプレイの大きさを導いています。iPhone Duoに向けてアプリを準備するは、マップのパネルが従う横並びのレイアウトを扱っています。Xcode 27.1 beta:iPhone Duoシミュレータでアプリを動かすは、ブリーフの継ぎ目のチェックが動くシミュレータを扱っています。
出典
-
pret、
pokered/home/overworld.asm、コミットd2704a6(OverworldLoopが反復ごとにDelayFrameを2回呼ぶこと、AdvancePlayerSpriteが反復ごとに2ピクセルを8回動かすこと、wWalkCounterが8であること、自転車では反復ごとにAdvancePlayerSpriteを2回呼ぶこと)、2026年10月4日閲覧、https://github.com/pret/pokered/blob/master/home/overworld.asm ↩↩↩↩ -
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 ↩↩↩↩ -
pret、
pokeemerald/src/event_object_movement.c、コミット731ad5b(ステップテーブル:歩きのsStep1Funcsが16エントリ、走りとなみのりが8、ダートじてんしゃと流れが6、マッハじてんしゃが4、最速が2。JUMP_DISTANCE_FARは2セルに32フレーム。sJumpY_Highは頂点で12ピクセル)、2026年10月4日閲覧、https://github.com/pret/pokeemerald/blob/master/src/event_object_movement.c ↩↩↩↩↩ -
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です。 ↩↩↩↩↩ -
著者による測定、2026年10月4日:
measure_gen12_routes.py(本記事用の著者の証拠フォルダ内)、出力gen12_routes.txt。pretpokered(d2704a6)からの入力:constants/map_constants.asm(ブロック単位の大きさを2倍してセルに)、maps/Route*.blk、Overworld_Collに照らしたgfx/blocksets/overworld.bst、草タイル$52とdata/tilesets/ledge_tiles.asm(1セルにつき8×8タイル1つ、左下のもの)、data/maps/objects/Route*.asm(OPP_クラスを持つobject_event行をトレーナーとする)、data/maps/headers/Route*.asm(接続)。pretpokecrystal(5beda23)から:maps/Route*.blk、CollisionPermissionTableを通したdata/tilesets/<tileset>_collision.asm(1ブロック4バイトを行優先と仮定)、maps/Route*.asm(OBJECTTYPE_TRAINERをトレーナーとする)。2026年10月5日に拡張(以前の出力はgen12_routes.pre-walls.txtとして保存):クリスタルの側面の壁、つまり衝突バイト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)は3つの変更のすべての組み合わせを実行する:壁だけで両方向とも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が赤のRoute 1を2倍の大きさで16ピクセルのグリッド付きで描画したもの(render_Route1.png、分析専用、著作権のあるアートから派生したもので非公開)を目で見て確かめた。注33の背後にある道路と町の面積もこのスクリプトによる。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
著者による測定、2026年10月4日:
measure_gen3_routes.py(本記事用の著者の証拠フォルダ内)、出力gen3_routes.txtとgen3_routes.json。pretpokeemerald(731ad5b)とpokefirered(037335f)からの入力:data/layouts/layouts.json(大きさ)、各道路のmap.binの全セル(ビット0〜9がメタタイル、10と11が衝突、12〜15が高さ)、プライマリかセカンダリのmetatile_attributes.binから引いたその挙動(エメラルドはu16で挙動がビット0〜7、ファイアレッドは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)。最短の歩きは幅優先探索による。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
著者による測定、2026年10月4日:
measure_travel.py(本記事用の著者の証拠フォルダ内)、出力travel.txtとtravel.json、pretpokeemerald(731ad5b)とpokefirered(037335f)に対して。(マップ, セル)の組の上で、継ぎ目、ワープ、段差を通す幅優先探索。最初のドアの下のセルから最後のドアまでで、そこへ踏み込む最後の一歩も数える(136行目、「+1: the step up into the door」、ドアへ踏み込む一歩で+1)。徒歩の秒数はセル数 × 16フレーム ÷ 59.7275ヘルツ。走りは2026年10月5日に拡張(すべての走りのセルを8フレームとしていた以前の出力はtravel.pre-ledgerun.txtとして保存)、最少フレーム数を求める2回目の探索で、一歩8フレーム、段差のジャンプ32フレーム。ファイアレッドのジャンプはJUMP_DISTANCE_FARでのJump2で、どの歩調でも32フレームだからである(src/field_player_avatar.cのPlayerJumpLedge、905行目。src/event_object_movement.cのDoJumpSpriteMovement、9094行目)。Route 4のポケモンセンターからハナダシティへの区間は1回のジャンプを含み2,528フレーム、42.3秒で、表のほかの行きの区間はどれも段差を飛ばない。いあいぎりの木、いわくだきの岩、かいりきの岩は、実行で別に指定しないかぎりそのセルを塞ぐ(「いあいぎり後」の実行ではそれらを取り除き、Route 2ではROUTE2_EAST_BUILDINGが開く)。フェードと戦闘は数えない。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
著者による測定、2026年10月4日。2026年10月5日に、
FillEastConnectionがコピーするとおり東側を8列読むよう、またFillNorthConnection、FillSouthConnection、FillWestConnection、FillEastConnectionが切るとおり各帯をバッファからはみ出すところで切るよう拡張。プライマリのみの数は22/38(エメラルド)と25/34(ファイアレッド)から24/38と24/34に動いた:measure_connections.py(本記事用の著者の証拠フォルダ内)、出力connections.txtとconnections.json、4つの逆コンパイルすべてに対して。すべてのマップ接続、各継ぎ目をまたぐタイルセットの一致(第3世代ではプライマリとセカンダリのセット、そして余白に入る隣の帯、つまり7行か7列、東は8列がプライマリのメタタイルだけを使っているかどうか)、オフセットを反転させた相互性、ゼロでないオフセット、赤のGATEとFOREST_GATEのタイルセットのマップ(data/maps/headers/*.asm)、クリスタルの環境GATE(data/maps/maps.asm)、そしてワープが2つの異なる屋外マップか、ひとつの屋外マップの2つの側へ通じる第3世代の屋内マップ。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
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でコトキタウン)、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 ↩↩↩↩↩↩↩ -
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 ↩↩↩↩↩↩↩↩↩↩ -
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 ↩↩↩↩↩↩↩ -
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(バトルフロンティアとみなみのことうはFLAG_LANDMARK_*フラグが立つまでMAPSECTYPE_NONE、1213〜1216行目)、731ad5b、2026年10月4日閲覧。壁の地図のレイアウトはscan_wall_maps.py(本記事用の著者の証拠フォルダ内、出力wall_maps.txt:ミシロタウンの2軒の家の2階と、すべてのポケモンセンターの1階)による。https://github.com/pret/pokeemerald/blob/master/data/event_scripts.s ↩↩↩↩↩↩↩↩ -
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 ↩↩↩↩↩↩↩↩↩↩ -
Kiradexのソース、
scripts/forge/town.pyの79行目と80行目(MARGIN = 12、WIDTH, HEIGHT = 40, 30)とそのBUILDINGSリスト(7つの建物、room:me、room:npc-*、hallへのドア、到着地点1つ)、2026年10月4日閲覧。非公開リポジトリ。 ↩↩↩↩↩↩ -
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 ↩↩↩ -
Blake Crosley「Pixel-Art Motion: Walks, Cameras and Doors on iPhone」、blakecrosley.com、2026年10月5日、第7節(「Where the walk stands today」:Kiradexの歩行コードのフレームモデル。走りは60ヘルツで1タイル10フレーム、毎秒6.00タイル、120ヘルツで19フレーム、6.32タイルで、各タイルの行き過ぎが捨てられるため。ドアの220ミリ秒の待ちとフェードのない階の変更。そしてブリーフの、1ティック1ピクセル、60ヘルツで1タイル16ティック、毎秒3.75タイルの歩きと、ドアと階を覆う段階的なベール)、https://blakecrosley.com/blog/pixel-art-motion-on-iphone ↩↩↩↩↩
-
本文中の測定値からの著者の計算。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が出力)。1セルあたりの秒数は16 ÷ 59.7275(0.27)、Kiradexの1タイルあたりは1 ÷ 4(0.25)。道のりの係数は、最短の歩きを道路の長辺で割ったもので、長いほうの方向と帰り道について、各方向に継ぎ目から継ぎ目への歩きがある9本の道路で計算(20セルのマップの最初の行から最後の行へのまっすぐな歩きは19歩、0.95)。短縮率は(行き − 帰り)÷ 行きで、2.38%(赤のRoute 3)〜44.12%(エメラルドのRoute 101)。道路ごとの歩けるセルに対するくさむらの割合は、2本の道路スクリプトの草と歩けるセルの数から。エメラルドのマップ上の町のマス数は、region_map_sections.jsonにある16の町と市の区画のwidthとheightから(1×1が10、1×2か2×1が6、計22)。Duoの内側のタイル数は2853 ÷ 96と2007 ÷ 96で、96は6ピクセルで16テクセル。中央にいるコレクターの前方のタイル数は、進行方向の軸に沿って見えるタイル数の半分。100ミリ秒の抜き取りは、60ヘルツで100 × 60 ÷ 1,000 = 6フレームに1枚。タイミングのしきい値は60ヘルツで2フレーム、33ミリ秒。どうぶつの森の16×16マスのエーカー5×6は80×96。ブリーフのエリアは44 × 14 + 24 × 60 + 36 × 20 + 30 × 20 = 3,376タイルで、40 × 30 = 1,200に対して。視界の半分は10月3日のタイル数を半分にして切り上げたもの。マップ画面のマス数は各エリアのタイル数を10で割って丸めたもの。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
著者による測定、2026年10月4日:
measure_grass_paths.py(本記事用の著者の証拠フォルダ内)、出力grass_paths.txt。くさむらのセルに入るとコスト1、それ以外の移動はコスト0とする0-1幅優先探索で、段差は一方向、2本の道路スクリプトのセルモデルとドアから到達できる越境点を使う。対象は赤のRoute 1、ファイアレッドのRoute 1、エメラルドのRoute 101と102。入り口のセルはprobe_grass_gateway.py(出力grass_gateway.txt)による。これは赤のRoute 1の南向きの探索を、草のセルを1つずつふつうの地面にして実行し直すもので、最小値を下げるのは入り口の最後の4行の8セル、1行に2セルだけだった。 ↩↩↩↩↩↩ -
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 ↩↩↩↩↩ -
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 ↩↩↩↩↩ -
pret、
pokeemerald/src/map_name_popup.c、731ad5b(POPUP_OFFSCREEN_Y 40、1フレーム2ピクセルのスライド、tOnscreenTimer > 120)、2026年10月4日閲覧、https://github.com/pret/pokeemerald/blob/master/src/map_name_popup.c 。合計190フレームは、タスクの状態をしきい値から数えた著者の数で、各状態は1フレーム長いか短い可能性がある。 ↩↩↩↩↩ -
pret、
pokered/data/maps/town_map_entries.asm(屋外のエントリ37、うち1つは未使用、屋内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 ↩↩↩↩↩↩↩ -
pret、
pokefirered/src/data/region_map/region_map_layout_kanto.hと3つのナナシマのレイアウト(1ページ22×15、フィールドとダンジョンの層)、src/party_menu.cとinclude/constants/party_menu.h(そらをとぶはFLAG_BADGE01_GET + fieldMoveで、FIELD_MOVE_FLYは2、つまり3つ目のバッジ)、src/region_map.c(GetMapsecTypeは場所のFLAG_WORLD_MAP_*フラグが立っているときだけMAPSECTYPE_VISITEDを返す、2957行目から。そらをとぶは訪問済みのマスだけを受け付ける。ナナシマのページはFLAG_SYS_SEVII_MAP_123とFLAG_SYS_SEVII_MAP_4567まで伏せられ、1028行目と1556行目、それらは1のしまのポケモンセンターのスクリプトが立てる。へそのいわとたんじょうのしまは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階、トキワシティの学校、いくつかの家)による。https://github.com/pret/pokefirered/blob/master/src/data/region_map/region_map_layout_kanto.h ↩↩↩↩↩↩↩↩↩↩ -
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 ↩↩↩↩↩↩↩ -
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 ↩↩↩ -
著者の調査ドシエ「Beyond the plaza: routes, map connections and districts in the canon」、2026年10月4日、第4節(「The brief for Kiradex」)、著者による統合:5つのエリアとその大きさ、距離の目標、接続の形式、継ぎ目・プレゼンス・柵の切れ目の計画、見つけもの、アーチの管理人、マップ画面、路面電車、作業の順序、13の受け入れチェック、そして含めないもの。Kiradexリポジトリの
docs/research/routes/01-routes.md、非公開。行きの帯は2026年10月5日に、ドシエの90〜120タイルから110〜120タイルに狭めた。理由は注66にある。ドシエのコピーにはまだ以前の帯が残っている。同じく10月5日に、ドシエのあとで決め、そのコピーにはないもの:アプリとサーバーで共有する8方向の歩行グラフ、草原の4本の生け垣、チェック6の全フレームの検査、作るべき作業としての拒否リスト、コインの見つけものの先送り。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
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で動くサーバー)。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Kiradexのソース、2026年10月5日閲覧(非公開リポジトリ):
Kiradex/World/TileMap.swift、325行目からのpath(from:to:)(8方向の移動。斜めのコストはFloat(2).squareRoot()で、348行目で、通り抜ける2つのタイルの両方が歩けないかぎり飛ばされる。最もコストの低い開いたタイルから展開する)と、server/app/rooms.py、52行目からのPlaza.path(66行目で4方向の移動に対する幅優先。そのdocstring:「the same walk the app takes」)。 ↩↩↩↩↩ -
著者の調査ドシエ「Beyond the plaza: routes, map connections and districts in the canon」、2026年10月4日編集、「Method」節と第5節(「What is measured and what is not」):共通の歩きの定義(一歩は1セル。段差は一方向で2セル。継ぎ目は、隣の向かい側のセルにそのドアのどれかから到達できる場合だけ数え、ワープのない隣については他の接続から1段階の深さで起点を取る。トレーナー、NPC、ストーリー上の障害は無視。なみのりなし。第3世代の高さは同じ高さか、どちらかが0か15に簡略化。ワープは踏み込んだときに発動。いあいぎりの木、いわくだきの岩、かいりきの岩は、別に記さないかぎり塞ぐ)、第1世代と第2世代のセルモデルの注意書き、地名表示のタイミングの注意書き、フレームレートの数値、分類の注意書き、ゲームのデータと照合していない二次資料、そして事実ではない読み。Kiradexリポジトリの
docs/research/routes/01-routes.md、非公開、著者の調査用の状態フォルダにコピーあり。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
gbdev、Pan Docs「Rendering」(1フレーム70,224ドット、「@ 59.7 fps」)、2026年10月4日に
pandocs-timing.txtとして保存、https://gbdev.io/pandocs/Rendering.html ↩ -
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 ↩↩ -
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を呼び、それはファイアレッドでは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 ↩↩ -
著者による測定、2026年10月4日、
measure_gen12_routes.py(赤:constants/map_constants.asmの$0B未満の11のマップIDに対するROUTE_1〜ROUTE_25、ブロック数×4。クリスタル:data/maps/maps.asmの環境ROUTE対TOWN、大きさはconstants/map_constants.asmから)とmeasure_connections.py(エメラルドとファイアレッド:map_type、大きさはlayouts.jsonから。エメラルドの11のMAP_TYPE_OCEAN_ROUTEマップ、45,600セルは陸の数値から除外。ファイアレッドの道路にはナナシマを含む)による。出力gen12_routes.txtとconnections.txt。 ↩↩↩↩↩↩ -
著者による測定、2026年10月4日:
measure_region_maps.py(本記事用の著者の証拠フォルダ内)、出力region_maps.txtとregion_maps.json(エメラルド:28×15のグリッド上で道路129マス、町22マス)。 ↩↩ -
Bulbapedia「Kanto Route 1」、攻略の節、2026年10月4日に
bulba-route1.txtとして保存、https://bulbapedia.bulbagarden.net/wiki/Kanto_Route_1 。草を最小にする探索の照合として一度だけ使用。 ↩ -
建物の記事のための著者の調査ドシエ、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(エメラルドのGetLedgeJumpDirection。段差は、その挙動が指定する方向にしか越えられない)、2026年10月3日。非公開。 ↩↩↩↩ -
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 ↩↩↩↩↩↩↩ -
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 ↩↩↩ -
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 ↩↩ -
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 ↩ -
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 ↩ -
Porymapのドキュメント「Editing Map Connections」、2026年10月4日に
porymap-connections.txtとして保存、https://huderlem.github.io/porymap/manual/editing-map-connections.html ↩↩ -
pret、
pokered/data/maps/objects/Route2Gate.asm(オーキド博士の助手と少年)、d2704a6、2026年10月4日閲覧、https://github.com/pret/pokered/blob/master/data/maps/objects/Route2Gate.asm ↩ -
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(いちばん上の行の2番目の位置にブロック14)、d2704a6、2026年10月4日閲覧、https://github.com/pret/pokered/blob/master/scripts/BluesHouse.asm ↩↩↩↩↩↩ -
pret、
pokecrystal/maps/CherrygroveCity.asm(案内のおじさんの贈り物、setflag ENGINE_MAP_CARD、72行目)とengine/pokegear/pokegear.asm(マップカードのPOKEGEAR_MAP_CARD_F。PokegearMap_CheckRegionは、プレイヤーがカントーのランドマークに立っているときだけカントーのマップを示す。カントーのそらをとぶの行き先はセキエイこうげんを訪れるまで伏せられる)、5beda23、2026年10月4日閲覧、https://github.com/pret/pokecrystal/blob/master/maps/CherrygroveCity.asm ↩↩↩↩↩ -
Stardew Valley Wiki「Modding:Maps」、2026年10月4日に
sdv-modding-maps.txtとして保存、https://stardewvalleywiki.com/Modding:Maps ↩↩ -
Stardew Valley Wiki「Pelican Town」、2026年10月4日に
sdv-pelican-town.txtとして保存、https://stardewvalleywiki.com/Pelican_Town ↩ -
Stardew Valley Wiki「Bus Stop」、2026年10月4日に
sdv-bus-stop.txtとして保存、https://stardewvalleywiki.com/Bus_Stop ↩ -
Stardew Valley Wiki「Cindersap Forest」、2026年10月4日に
sdv-cindersap.txtとして保存、https://stardewvalleywiki.com/Cindersap_Forest ↩ -
Stardew Valley Wiki「Backwoods」、2026年10月4日に
sdv-backwoods.txtとして保存、https://stardewvalleywiki.com/Backwoods ↩ -
Stardew Valley Wiki、「Railroad」に表示される場所のナビゲーションボックス、2026年10月4日に
sdv-railroad.txtとして保存、https://stardewvalleywiki.com/Railroad 。著者の数えで26の場所。 ↩ -
Stardew Valley Wiki「The Mountain」(最初の2つの出口、春の5日の鉱山、夏の3日の地震のあとの鉄道、工芸品の部屋のバンドルか25,000gでの採石場の橋)、2026年10月4日に
sdv-mountain.txtとして保存、https://stardewvalleywiki.com/The_Mountain ↩↩↩↩ -
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 ↩↩ -
Stardew Valley Wiki「Speed」、2026年10月4日に
sdv-speed.txtとして保存、https://stardewvalleywiki.com/Speed 。このページには単位がない。 ↩ -
Nookipedia「Acre」(16×16マスのエーカー、横5エーカー縦6エーカーのゲームキューブ版の町、A-3の駅、ラベル、入ったときの魚と虫の出現と6マスでの消滅、後の作品の町の大きさ)、2026年10月4日に
nook-acre.txtとして保存、https://nookipedia.com/wiki/Acre ↩↩↩↩↩ -
Nookipedia「Map」、2026年10月4日に
nook-map.txtとして保存、https://nookipedia.com/wiki/Map ↩ -
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 ↩ -
zladx、LADX-Disassembly wiki「Game engine documentation」、2026年10月4日に
ladx-engine.txtとして保存、https://github.com/zladx/LADX-Disassembly/wiki/Game-engine-documentation ↩↩↩ -
zladx、LADX-Disassembly wiki「Maps data format」(2バイトの部屋ポインタからなる512バイトのフィールドのマップ、10×8のオーバーレイ)、2026年10月4日に
ladx-maps-format.txtとして保存、https://github.com/zladx/LADX-Disassembly/wiki/Maps-data-format ↩ -
Blake Crosley「Pixel-Art Worlds on iPhone: What the 16-Bit Masters Knew」、blakecrosley.com、2026年10月3日(第5節:RealityKitのレシピ、マップ用の1つの
MeshDescriptorメッシュ、RealityViewの既定値、Appleの仕様ページとXcode 27のシミュレータのプロファイルから計算した倍率の表、11ポイントのテキストの最小値とSwiftUIのテキスト、不透明度のアニメーションのバグとそのベール、バンドル内でのXCUIScreenのキャプチャ。「Since publishing」:アプリとサーバーに書き出す1つの文字のマップ。著作権と特許についてのよくある質問)、https://blakecrosley.com/blog/pixel-art-world-on-iphone ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple「iPhone Duo: Technical Specifications」、2026年10月4日に
apple-duo-specs.txtとして保存、https://www.apple.com/iphone-duo/specs/ ↩ -
Apple、ヒューマンインターフェイスガイドライン「Designing for games」(ドキュメントのJSON経由)、2026年10月4日に
hig-games-plain.txtとして保存、https://developer.apple.com/design/human-interface-guidelines/designing-for-games ↩↩ -
Kiradexのソース、
Kiradex/World/PlazaStage.swift、2026年10月5日閲覧(非公開リポジトリ):132行目と133行目(ドアのワープでTask.sleep(for: .milliseconds(220))、そのあとonWarp(warp)、フェードなし)と698〜700行目(floor:のワープは新しい階をその場で設定し、フェードなし)。 ↩ -
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 ↩↩ -
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日閲覧。非公開リポジトリ。 ↩↩ -
著者による測定、2026年10月5日:
measure_meadow_gate.py(本記事用の著者の証拠フォルダ内)、出力meadow_gate.txt。ブリーフの中央広場、草原の小道、湖畔を、第7節の大きさでひとつのグリッドに結合する。中央広場はフォージが出荷するとおり(town.json、40×30、到着地点は19列13行、サーバーの歩ける文字)で、共有する辺に沿って北の柵を開ける。草原の小道は24×60で、中央広場の西端から4タイル内側に置き、小径がホールとその東の家のあいだの芝生に出るようにする。小径は幅2タイルで東側の生け垣の向こうにあり、湖側の端に門を一方通行の辺として置く。残りは4本の生け垣が草原の12、24、36、48行目で横切り、幅2タイルの切れ目をあらゆる位置で試す。湖畔は36×20で、小道の中央に合わせ、北半分は湖、桟橋は幅2タイルで小径と一直線に置き、陸側のタイルまで測る。アプリのグラフ(TileMap.path)で歩く:8方向、斜めのコストは√2で、通り抜ける2つのタイルのどちらかが塞がれていれば拒否。門は小径から湖へ向かう一歩をすべて拒み、湖からの一歩はまっすぐのものだけ受け入れる。うねりは、小径の西側での、南の辺から北の辺への草原自身の最短の歩き。2本の生け垣(草原の20行目と40行目)では、400通りの位置すべてで59.00〜66.46タイル、3本(15、30、45行目)では59.00〜79.77タイル(8,000通りのうち6通りが78〜90)、4本では59.00〜95.43タイル(160,000通りのうち5,912通りが78〜90)。これらの範囲は等間隔の生け垣についてのもので、不均等な間隔は同じ関数でもっと強くうねる(r7_uneven_probe.py、10月5日、出力r7_uneven_probe.txt:0行目と2行目の2本で77.00、20、22、24行目の3本で95.00に達する)。3本の生け垣、草原の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。つまり3本の生け垣は5つの位置ですべての目標を満たし、著者が選んだ4本は4,111の位置で満たす。4本の生け垣の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タイル。門を双方向に開けると歩きは等しくなる(各生け垣の本数について1つのレイアウトで、どちらの方向も88.07)。オフセット0〜16タイルのすべてと桟橋の両方の位置で、最短の行きは107.18、最短の帰りは88.07。毎秒4タイルで、110タイルと120タイルは27.5秒と30秒。同じ出力は以前のモデルとも突き合わせている。保存したコピーから実行すると、2本の生け垣での4方向の幅優先探索は125通りのレイアウトを残し、行き113〜119、帰り91、比0.765〜0.805。その125通りを8方向で歩くと、行き97.18〜99.67、帰り88.07、比0.884〜0.906で、0.8のものはひとつもない。以前のモデルは、探索が返したいずれかの最短経路の草原での歩数をうねりとして数えており、それは同点のときに変わりうる。端から端へのうねりは変わらない。ブリーフが記述していない配置も同じ出力で掃引した:桟橋を岸の中央に置くと最良の比は0.721(オフセット4、5,912通りのうち2,182通りが0.8以下)、小径が建物にぶつかる配置では門は何も節約しない。 ↩↩↩↩ -
Apple Developer Documentation「preferredFrameRateRange」(
CADisplayLinkのインスタンスプロパティ、Core Animation。iOSとiPadOS 15.0以降)、2026年10月4日保存(Discussion:ディスプレイリンクはその範囲内でコールバックしようとできるかぎり努めるが、システムはハードウェア、ほかの作業、低電力モード、温度状態、アクセシビリティの設定も考慮し、既定では範囲はディスプレイの最大リフレッシュレートに等しい)、https://developer.apple.com/documentation/quartzcore/cadisplaylink/preferredframeraterange ↩↩