Edeny Arcadia Ch.2 Lab
← Back to Blog

おにぎりで穴に落ちて、
ゴーレムを泣かせた話
Edeny Arcadia 第二章 — 古代遺跡の祠

PROLOGUE

第一章を終えて、地下へ落ちた

第一章でのっぱらに降り立ち、影のボスを倒して英雄になったエデニー。次なる目標は楽園の建材集め。第二章のテーマは「古代遺跡の祠」——のっぱらの南端に眠る地下ダンジョンだ。

そして入場フローがバカっぽい。おにぎりを拾おうとしたら地面が崩れて穴に落ちる。「地面がっ──ズドーン!!」とフェードアウトして気づいたらダンジョンにいる、という流れにした。

「倒したのに泣いてる気がする」——そういうエンディングを作るために、第二章はある。

第一章のボスは「影」という記号的な存在だった。第二章のボスには名前も感情もある。アングラゴーレム——何百年もそこを守り続けた古代の守護者だ。

BUILD

既存コードに「最小の傷」でダンジョンを追加する

第二章の技術的な課題は「フィールドとダンジョン、2つのマップを共存させること」だった。既存のコードはフィールドマップしか想定していない。

解決策はgetMap()関数を1つ作ることだった。現在どちらのマップにいるかを返すだけの関数で、既存コードのMAP参照を全部getMap()に差し替えるだけで、移動・描画・インタラクション処理が両マップに対応した。

// マップ切替の核心 — これだけで既存コード全体が両対応になる let currentMap = 'field'; function getMap() { return currentMap === 'dungeon' ? DUNGEON_MAP : MAP; }

切替変数は currentMap の1つだけ。追加するたびに分岐が増えるのではなく、1つの変数を変えるだけで世界が変わる。「既存コードへの影響を最小に保ちながら世界を広げる」という設計が決まった瞬間だった。

章の管理も同じ発想で整理した。chapter変数を1〜2で持ち、クリア画面・看板のセリフ・キー処理をすべてこの変数で分岐する。

BGMもbgmModeの文字列で切り替える。'dungeon'モードは低音寄りのsine波で、フィールドとは違う雰囲気を一発で作れる。startBgm('dungeon')の1行で空気が変わる。

STORY

ゴーレムが守り続けていたもの

ダンジョンはT字分岐構造で、左腕・右腕・最深部に素材を1つずつ配置した。3つ全部を集めた瞬間に自動でボス出現スクリプトが走る。

アングラゴーレムの外見は「石肌・神官ローブ・蒼い悲しい目」。バトル中、涙が落ちるアニメーションが流れる。彼はHP80を持ち、プレイヤーに攻撃してくる。でも見た目と動きが、明らかに「倒されたくない」と思わせない。

勝利ダイアログに、この章で一番時間をかけた9行がある。

アングラゴーレム:「……ぎゅ、ぎぃ……(崩れる音)」
EDENY:「……なんか、かわいそうやな。」
CLANA:「ここを何百年も守ってたんですね。誰にも感謝されずに。」
EDENY:「……黙ってろ。(目をそらす)」
アングラゴーレム:「…………の、っぱら……まも……る……」
CLANA:「あ……砂が……目に……」
EDENY:「砂が入った(俺も)」
CLANA:「嘘おっしゃい。」
EDENY:「……行こか。楽園、作ったる。のっぱらに。」

エデニーは「金の亡者が気づいたら英雄になってた」キャラだ。素直に泣けない。でも「砂が入った」という言い訳を、クラナも同じように使う。二人が同じ言葉で涙を隠す対になった構造にした。

最後の「楽園、作ったる。のっぱらに。」——これは第一章からエデニーが言ってきた台詞だ。でも今回だけは、その続きがある。「あいつの分も含めて。」それが第二章でエデニーが一番らしくない発言だった。

TROUBLE

5件のバグ。全部「設計の隙間」から生まれた

BUG 01
ダンジョンから出たら、二度と戻れなくなった
おにぎりに触れたとき、そのタイルを草地に書き換えてしまっていた。ダンジョンから出ると、もともとおにぎりがあった場所は普通の草原になっていて再入場する手段がゼロ。

修正:exitDungeon()の中で洞窟入り口タイル(T.CAVE)を設置するようにした。消費型の仕掛けタイルを再入場の入り口にしてはいけない——というのが教訓。
BUG 02
第二章で看板を読んだらクリア画面になった
第一章の看板にはgameState = 'complete'を発火するコールバックがついていた。chapter変数を確認しないまま走るので、第二章でも同じ看板を読むとクリア画面が出る。

修正:chapter === 2のときは短い別セリフを流すだけに分岐。「この先でいつか変わりますよ。私たちが作りますから。」——クラナらしい、静かな一行に変えた。
BUG 03
runScript中にボストリガーが割り込んだ
階段を調べるスクリプト実行中にcheckDungeonBossTrigger()を直接呼んでいた。runScriptは非同期的に進行するため、スクリプト実行中にトリガーが呼ばれるとスクリプトごと上書きされてしまう。

修正:ボストリガーは各アイテム取得後のonDoneコールバックから呼ぶ方式に統一。「スクリプト実行中に直接呼ばない」というルールを徹底した。
INSIGHT

拡張しやすいコードとは何か

第二章で追加した技術要素を振り返ると、共通のパターンが見える。「切替変数を1つ増やすだけで、世界が広がる」設計だ。

currentMapでマップが切り替わる。chapterで章が切り替わる。battleTypeでボスが切り替わる。bgmModeでBGMが切り替わる。どれも「新しい場合を追加するコスト」がほぼゼロだ。

第三章を作るとき、currentMap = 'dungeon2'と書けばいい。chapter = 3にすれば、クリア画面もセリフも切り替わる。「今から追加しやすいように書く」ことは、「今すぐ動く」のと同じくらい大事だと思う。

SUMMARY

おにぎりで穴に落ちて始まる第二章に、ダンジョン・素材3個・アングラゴーレムを詰め込んだ。技術面ではgetMap()によるマルチマップ切替battleTypeによる敵の切替chapter変数による章管理を実装し、既存コードへの影響を最小に保ちながら世界を広げる設計が定まった。

そしてゴーレムの「砂が入った(俺も)」——金の亡者エデニーが初めて本音を出した瞬間だった。のっぱらに楽園を。あいつの分も含めて。 そう言えるキャラになるまでに、第一章と第二章があった。

ALL UEFN × Verse Lab Log