AIとゼロから作る脱出ゲーム開発日記 第10話:「誰でも差し替えられるテンプレート」に仕上げようとしたら、扉が1枚すり替わっていた話

Claude Codeのターミナル画面の前に、暗い木の扉と明るい玄関扉のアイコンが並び、玄関扉に虫眼鏡が重なっている開発デスクのイメージ画像。 開発日記

前回までのあらすじ

前回は、第2弾ゲーム「おでかけ!わすれもの大作戦」に隠しアイテムと隠し部屋を入れ、また出てきた透過バグとレイアウト調整に追われた回でした。

2本のゲームを作ったことで、エンジンにはひと通りの機能がそろいました。そこで今回は、Web Escape Engine Liteの第1弾を締めくくる作業に入ります。目標はシンプルで、「買った人が、自分のゲームに作り替えられる状態にする」こと。手順書を書いて、販売用のZIPを作るだけ……のはずでした。

結果から言うと、この「最後の仕上げ」が、連載でいちばん冷や汗をかいた回になりました。

第1章:手順書を書いたら、長すぎて誰も読まない代物になった

まず、エンジンをどこまで説明するかを決めるために、Claude Code(実装担当)に2本のゲームのエンジン部分を比べてもらいました。

意外なことに、engine.jsやgame.jsなどのエンジン部分は、2本のゲームでバイト単位まで完全に同じでした。違うのはタイトルなどの文言だけ。「おでかけ用に追加した機能」も、実は最初のテンプレート側にそのまま入っていて、使われていなかっただけでした。エンジンを一本化する作業は要らない、という嬉しい結果です。

一方で、説明書(README)に載っていない機能が十数個も見つかりました。当たり判定のない飾り(decorative)、画像の左右反転(flipX)、部屋に入ったときのヒント(entryHint)など、2作目で実際に使った機能ばかりです。

そこで、それらを全部入れた「シナリオの書き方ガイド」を作ってもらいました。出てきたのは482行。内容は正確でしたが、読んでいて途中で気づきました。

これは「エンジンに何ができるか」の説明であって、「買った人がやりたいこと」の説明ではない。

たとえば「タイトルを変えたいだけ」の人でも、設定項目の説明を上から順に読んで、タイトル画面の文言の章にたどり着くまで、全体の半分以上を読むことになります。

そこで構成を丸ごと変えました。説明書は次の3本だけにしています。

  • README:起動方法と、「書き換えるのはconfig.jsとassetsフォルダだけ」という地図。1画面に収める
  • guide.md:「タイトルを変えたい」「暗証番号を変えたい」「罠を置きたい」など、やりたいこと別の10のレシピと、公開前のチェック
  • reference.md:全項目の辞典。レシピにないことをしたい人向け

レシピは「どこを開いて、どの行を書き換えるか」だけを書き、「なぜ便利か」という説明は削りました。

それでも、未経験の人が実際にやると詰まる箇所がいくつも見つかりました。たとえば暗証番号のレシピでは、金庫の番号だけを書き換えると、引き出しのメモには古い番号が残ってしまいます。そうなるとプレイヤーは正解を知る手段がなく、ゲームが詰みます。こうした「書いてある通りにやると壊れる」箇所を1つずつ潰していきました。

第2章:「この画像、売っていいんだっけ?」

手順書がまとまり、次は販売用ZIPの準備です。ここで、ゲームに入っている画像・音声のクレジットを整理しようとして、手が止まりました。

音声はFreesoundの素材で、出典とライセンスがすべて記録に残っていました。ところが、画像については、どのサービスのどのモデルで作ったのか、記録がどこにもなかったのです。2本のゲームを合わせると61点、そのうち販売するテンプレートに入るのは18点です。

画像生成AIは、サービスやモデルによって「商用利用してよいか」「素材として再配布してよいか」の条件が違います。テンプレートとして売るということは、画像ファイルそのものを買い手に渡すということです。出どころが分からないまま売るわけにはいきません。

画像を作ってくれていたのは、OpenMontageを使っている別のClaude Codeセッションです。生成に使ったコードを確認してもらったところ、61点すべて、fal.ai経由のRecraft V4というモデルで作られていたことが分かりました。

fal.aiのモデルページには商用利用可と書かれていて、規約本文も確認しました(2026年9月8日更新版を10月3日に確認)。ChatGPTにも別の角度から読んでもらって、整理できたのは次の点です。

  • 商用利用は認められている
  • ただし、生成した画像がオリジナルであることや、他人の権利を侵害しないことは保証されていない
  • もし誰かの作品に似てしまった場合の責任は、使う側にある

つまり大事なのは、「特定の作品やキャラクターに寄せた指示をしていない」と、記録で示せることです。そこで、OpenMontage担当に、生成に使ったプロンプトを作品名・キャラクター名で検索してもらいました。結果、特定の作品名・キャラクター名の指定はありませんでした。唯一、タイトル画面の背景に「Dracula-style castle(ドラキュラ風の城)」という様式の形容が入っていましたが、プロンプトの原文は「A distant gothic Dracula-style castle」で、「ゴシックな古城」というジャンルの表現として入れたものだと考えています。

正直に書くと、これは最初に画像を作る時点で記録しておくべきことでした。 最後になって慌てて調べ直した形です。生成コードが残っていたので、ほぼ全部の画像の出どころをたどれましたが、記録はあくまで後から復元したものです。数点は、生成後に手直しされた可能性があり、元ファイルと完全には一致しませんでした。今後は、画像を生成するたびにモデル名・日時・プロンプトの場所を記録する機能を、生成用のツールに追加しています。

ついでに、ZIPに入れる音声も見直しました。解錠音として同梱していた音声が、8.8秒の中にカチャ音が7回ほど続く長いものだったので、ゲームには使わずZIPから外しています。

第3章:白い扉の謎

出どころの調査を進める中で、Claude Codeから気になる報告が上がってきました。

「テンプレートのdoor.pngは、実際には白い玄関ドアです。城のゲームなのに雰囲気が合っていません」

テンプレートの扉は、暗い木材に鉄の金具が付いた重厚な扉のはずです。第5話までのブログに埋め込んだゲームも、その扉でした。

gitの履歴を見ると、9月24日に「Update castle door artwork(城の扉の絵を更新)」というメッセージで差し替えられていました。一見、意図した更新に見えます。でも、そんな依頼をした覚えはありません。

ここから、記録を1つずつ照らし合わせていきました。

  1. コミットの日付はあてにならなかった:第9話で書いたとおり、テンプレート側は長いあいだ丸ごとコミットされていませんでした。9月24日は、溜まっていた未コミットの変更をまとめて整理した日でした。画像ファイルが実際に書き換わったのは、その15日前の9月9日10時20分です。
  2. 中身は「おでかけ」の玄関ドアだった:9月9日の10時6分に、OpenMontage側で「おでかけ」用の玄関ドアを生成した記録がありました。プロンプトは「明るい家の玄関ドア」。画像サイズも一致し、ファイルが書き換わったのは生成の13分後です。元の生成ファイルが残っていないのでバイト単位の一致は取れませんが、ほぼ確実と言えます。
  3. 書き込んだのは、AI自身の操作だった:OpenMontage担当のClaude Codeに自分の作業記録を調べてもらうと、おでかけ用の素材を置くコマンドの置き先が、テンプレート側のフォルダになっていたと報告してきました。同じdoor.pngという名前だったため、確認なしに上書きしていたのです。
  4. 整理のときにも見逃された:9月24日の整理では、テンプレートに紛れ込んだ「おでかけ」の素材を、どこからも使われていないファイルとして削除していました。ところがdoor.pngはテンプレート側でも使っている名前なので、削除の対象から漏れました。そして、そのコミットには中身と合わない「城の扉の絵を更新」というメッセージが付けられていました。

しかも白い扉は、第7話で直したはずの透過バグが残った古い版でした。扉の中が透けて、後ろの壁が見えている状態です。

最終的な決め手になったのは、ConoHaに公開している第5話のゲームでした。私がサーバーから元の扉を取ってきてハッシュ(ファイルの指紋のようなもの)を比べてもらうと、gitに残っている元の扉とバイト単位で一致しました。さらに、8月15日にRecraft V4で生成した元画像を、ゲームで使っている大きさに縮小して比べると、見た目の差はゼロでした。生成した時期やプロンプトの内容とも合っていたので、元の扉の出どころもほぼ確実になり、安心して元に戻せました。

振り返ると、AIが書いたコミットメッセージも、AIが事後にまとめた記録(扉の生成日やサイズ)も、どちらも間違っていました。最後に頼りになったのは、ハッシュとファイルの更新日時という「実物の記録」です。この連載で何度も書いてきた「AIの報告を鵜呑みにせず、実データで裏を取る」を、いちばん痛感した出来事でした。

第4章:二度と起こさないための仕組み

扉を戻して終わり、にはしませんでした。今回の事故は、4つの穴が重なって起きたものだったからです。

穴対策
素材を作る側が、ゲームのフォルダに直接書き込めた納品は受け取り用のincoming/フォルダだけに置く。ゲームへの反映は、実装担当が指示を受けて行う
同じ名前のファイルを確認なしに上書きした置き先に同じ名前のファイルがあれば、上書きせずに止めて報告する
長期間コミットしなかったので、変化に気づけなかった作業の区切りごとにコミットし、セッションの最後に未コミットの変更がないか確認する
中身と合わないコミットメッセージが付いた確認した事実だけを書く。見ていない変更は「中身未確認」と書く

この方針は、それぞれのClaude Codeが起動時に必ず読むCLAUDE.mdというファイルに書きました。AIはセッションが変わると前の会話の約束を覚えていないことがあるので、口頭で「もうしないで」と言うだけでは再発します。ファイルに書いておけば、毎回読み込まれます。

素材を作る側のCLAUDE.mdには、「既存の作品名・キャラクター名や、特定の作品に寄せた表現をプロンプトに使わない」というルールも書きました。第2章で確認したことを、記憶ではなくルールとして残すためです。

2つのセッションの間の受け渡しルールは、Obsidianのノート1枚にまとめ、両方のCLAUDE.mdからそのノートを参照する形にしました。ルールが2か所に分かれて食い違うのを防ぐためです。

あわせて、販売用ZIPを作るスクリプトに、作る前の自動チェックを入れました。1つでも引っかかったら、ZIPは作られません。

  • デバッグ表示(チート用のボタン)が切られているか
  • 設定ファイルが参照している画像・音声が全部そろっているか
  • 音声がすべてクレジットに載っているか、ライセンスに問題がないか
  • 画像・音声のハッシュが、記録したときのファイルから変わっていないか(今回の扉のような、意図しない差し替えに気づくため)
  • 説明書の画像リンクが切れていないか
  • 文字が背景に沈まず読めるか(次の章で詳しく)

最後に、3つのルート(ノーマルエンド、罠でゲームオーバーしてリトライ、トゥルーエンド)を自動で通しプレイし、全画面のスクリーンショットを撮って、人間が目で確認します。

並べてみると、どれもこの連載のどこかでつまずいた点です。第2話で、デバッグ表示の初期値がオンのままになっていたのを公開前に見つけたこと、そして今回の扉。失敗のたびにチェック項目が1つずつ増えてきた、と言ってもいいかもしれません。

第5章:最後に見つかった「読めない文字」と「鳴り続けるBGM」

チェックの仕組みが揃ったところで、スクリーンショットを見たClaude Codeが、もう1つ気づきました。ライトモードのタイトル画面で、小さな見出しと説明文が、背景のグレーに沈んで読みにくいのです。

第2話で、スマホがライトモードだとタイトルの文字が読めなくなる不具合を直したことがありました。それと同じ種類の問題です。

目で見た印象だけで判断すると、また見落としが出ます。そこで、文字と背景の色の差(コントラスト比)を数値で測ることにしました。基準には、Webでよく使われるWCAGというルールを使っています。普通の文字は4.5:1以上、大きい文字や矢印などの記号は3:1以上、という基準です。

測ってみると、ライトモードのタイトル画面では、小さな見出し「ESCAPE GAME TEMPLATE」が1.11:1、説明文が2.27:1でした。見出しは、ほとんど背景と同じ色です(大きなタイトル文字は問題ありませんでした)。ほかにも、部屋を移動する矢印や「戻る」ボタン、所持品欄の「なし」など、基準を下回る文字がいくつも見つかりました。特に移動の矢印は、見えないとプレイヤーが「この先に進めない」と思って遊ぶのをやめてしまう部分です。

すべて直したあと、ライトとダークの両方で全14画面、118か所を測り直して、全部が基準を満たしました。このチェックもZIP作成に組み込んだので、今後色を変えて読めなくなれば、自動で止まります。

もう1つ気づいたのがBGMです。ブログを開いたまま、別のタブで作業をしていたら、裏でBGMがずっと鳴り続けていました。調べてみると、タブを切り替えても、記事をスクロールしてゲームが画面の外に出ても、BGMは止まらない作りでした。記事を読み進めている読者にとっては、かなり気になるはずです。

そこで、「タブが表示されていて、かつゲームが画面に見えているときだけ鳴らす」ようにしました。どちらかが外れると止まり、戻ると止まった位置から再開します。

なお、この対応はまだテンプレート側だけです。第6〜9話の「おでかけ」の埋め込みには入っていないので、そちらはBGMが鳴りっぱなしのままです。

🎮 今回のバージョン

販売用テンプレートと同じ中身の「密室からの脱出」です。元の重厚な扉に戻り、文字の読みやすさとBGMの止まり方も改善しています。

遊んでいる途中で、記事を下にスクロールしたり、別のタブに切り替えたりしてみてください。BGMが止まり、戻ると続きから鳴るはずです。

💬 読者へのヒアリング

今回はライトモードとダークモードの両方で文字の読みやすさを測りましたが、端末や画面の明るさによって見え方は変わります。

  • 読みにくい文字や、見えにくいボタンはありませんでしたか?
  • スクロールやタブの切り替えで、BGMはきちんと止まりましたか? スマホでホーム画面に戻ったときはどうでしたか?

気づいたことがあれば、コメントで教えてください。

まとめ&次回予告

「最後の仕上げ」のつもりで始めた今回は、手順書の作り直し、画像の出どころの確認、すり替わった扉の調査、再発防止の仕組み作り、そして読めない文字とBGMの修正と、想像よりずっと長い道のりになりました。

いちばんの収穫は、扉の件で、AIが自分の作業で起こした事故の原因を、AIと人間の分担で突き止められたことです。AIは自分の作業記録や生成コードを調べ、私はサーバーから公開中の実物を取ってきて、AIに照合を頼む。それができたのは、ハッシュやファイルの更新日時、生成コードといった実物の記録が残っていたからでした。AIで素材を量産するなら、最初から出どころを記録しておく。これは、同じように個人開発をしている方にも役立つ教訓だと思います。

これで、Web Escape Engine Liteの第1弾は、手順書・素材・自動チェックまで揃った「売れる状態」になりました。

次回はいよいよ販売開始編です。どこで売るのか、いくらにするのか、買った人に何を許可するのか。作るのとはまったく違う種類の悩みが待っています。


次回:第11話「テンプレートを売ってみる:販売先選びから公開まで」

コメント

タイトルとURLをコピーしました