AIとゼロから作る脱出ゲーム開発日記 第3話:本物の素材を入れたら、存在しなかったはずのバグが一気に噴き出した話

Claude Codeのターミナル画面とスマホに、ファイルサイズの圧縮・音量アイコンのバツ印・床とドアのズレを示す表示があるデスクのイメージ画像。 開発日記

前回までのあらすじ

前回は、危険な仕掛けを追加してAIのサンプルコードの見落としを2つ拾い、スマホ向けの操作方式を設計して、公開後の実機テストでさらに2つの不具合を見つけて直しました。ここまでの見た目は、まだグラデーションの壁とSVGで描いた図形だけの、procedural描画によるものです。

今回はその procedural描画を、初めて本物の背景・オブジェクト画像に差し替えた回です。結論から言うと、「グラデーションの壁だった間は絶対に起きようがなかった」種類のバグが、実素材を入れた瞬間に次々と噴き出すことになりました。

第1章:納品直後に判明した「重さ」の問題

OpenMontage(別プロジェクトのClaude Codeが担当しているアセット制作パイプライン)に背景・オブジェクトの制作を依頼し、背景1点とオブジェクト11点が納品されました。ここまでは順調でした。

ところが、納品されたファイルを確認したところ、12ファイル合計で13MBもありました。実際にゲーム画面上で表示するサイズは大きくても220pxほどなのに、納品されたオブジェクト画像は軒並み1024px前後の高解像度で作られていて、4倍から20倍近く過剰なサイズだったのです。「ZIPを解凍してダブルクリックすればすぐ動く」というこのテンプレートの売りに、これでは真っ向から反してしまいます。

実際に表示するサイズの2倍程度(長辺480px上限)にリサイズし、背景画像はJPEG形式に変換。これだけで13MBから約2MBまで軽量化できました。

ちなみに、この過程で「透過PNGのはずなのに白い背景に見える」という指摘も出ましたが、実際にアルファチャンネルを解析してみると正しく透過されていて、単に確認に使っていたビューアの表示上の問題だと分かりました。見た目の印象だけで判断せず、実際にデータを確認する大切さを再認識した一幕です。

第2章:「file://で音が鳴らない」——商用テンプレの根幹を突くバグ

軽量化が済んだところで、BGMと効果音も実ファイルに差し替えました。ところが、音が合成音のままで変わっていないという報告が入りました。

音の変化が確認できない、という報告を受け、最初はブラウザのキャッシュを疑い、index.htmlのCSS/JS読み込みに?v=Nというキャッシュ回避用のクエリを追加しました。ところが症状は直らず、あらためてどうやって確認しているか尋ねたところ、「ZIPを解凍してindex.htmlを直接開いている」という答えが返ってきました。ここでようやく本当の原因に気づきます。

原因を追ってみると、音声を読み込む処理がfetch()とWeb Audio APIのdecodeAudioDataを組み合わせた実装になっていたことが分かりました。fetch()は、ページ自体がfile://として開かれている場合、たとえ同じfile://上にあるファイルへのアクセスであっても、ブラウザのセキュリティ制限によってブロックされてしまいます。しかも、そのエラーは.catch()の中で静かに握りつぶされていて、画面には何も表示されないまま、合成音のプレースホルダーへこっそりフォールバックしていました。

これまでの動作確認はすべてhttp://localhost経由のローカルサーバーで行っていたため、このテンプレート最大の売りである「ZIPを解凍してファイルをダブルクリックするだけで直接開く」という使い方そのものが直撃していたことに、まったく気づけていなかったのです。対策として、fetch()ベースの読み込みをやめ、<img><script>と同じ通常のリソース読み込み経路を使う<audio>要素に切り替えることで解決しました。

キャッシュ対策を先に打ったのに直らず、掘り下げてみたら実はもっと根本的なバグだった——検証環境を一つに絞っていたことで、一番肝心な使い方だけが盲点になっていた、今回のサイクルの中でも特に肝を冷やした出来事でした。

第3章:背景を実写にしたら、部屋のあちこちがズレていた

背景をさらに2点(左の壁、金庫のズームアップ画面用)、装飾オブジェクトを3点(時計・窓・観葉植物)、BGMとSEも3点追加で納品してもらい、組み込みました。

ここで「部屋の背景の雰囲気が違いすぎる」という指摘が入ります。最初に作った正面の壁は質素な書斎の雰囲気だったのに対して、後から追加した左の壁や金庫周りの背景は金箔装飾の効いたゴシック調で、まったくトーンが揃っていなかったのです。正面の壁もゴシック装飾のトーンに作り直し、あわせてタイトル画面専用の背景(崖の上に建つ古城)も新規に用意しました。このタイミングで、エンジン側にタイトル画面用の背景画像を差し込む仕組みも新設しています。

背景を実写画像に差し替えたことで、今度は「ドアが床から浮いて見える」という不具合が発覚しました。procedural描画の時代は、床の位置を計算上の座標(デザイン座標で560×0.68≒381px)を基準に決めていたのですが、実写画像の実際の床のラインはその位置とぴったり一致するとは限りません。画像にグリッドを重ねて実測し、ドアの位置を修正しました。同じ理由で、金庫のオブジェクトも床から浮いて見えるという指摘があり、左寄りに配置していた燭台の隣へ再配置しています。

さらに、ドアを部屋の中央のアーチ部分に動かした際、「ドアが開くアニメーションは、扉のスプライトを横方向に縮めて透明にしているだけで、背景側に開いた後の絵を別途用意しているわけではない。つまり、ドアの真下にある背景がそのまま透けて見えてしまう」という構造上の限界にも気づきました。実は最初にドアを配置していた位置は、右側にある燭台のちょうど真上で、そのままドアを開けていたら燭台が宙に浮いて見えるはずだったのです。指摘される前に発見できたのは幸いでしたが、窓・時計・引き出しも含めて、燭台と重ならない位置へあらためて配置し直しました。

🎮 今回のバージョン

procedural描画だった部屋が、初めて本物の背景・オブジェクト画像になったバージョンです。重さの問題もfile://の音声バグも解消済みなので、ぜひZIPを解凍してダブルクリックで開く体験を試してみてください(もちろんブラウザ埋め込みでも遊べます)。

💬 読者へのヒアリング

今回直したfile://での音声バグは、ローカルサーバー経由でしか確認していなかったために長く気づけませんでした。もし実際にファイルをダウンロードして遊んでみて、音が鳴らない・画像が表示されない・重くて開くのに時間がかかる、といった環境依存の不具合に気づいたら、ぜひ使っているOSやブラウザとあわせて教えてください。

まとめ&次回予告

今回のサイクルを通して見えてきたのは、procedural描画の時代には存在しようがなかったバグのクラスが、実素材を入れた瞬間に一気に噴き出したという事実です。床の位置、file://での音声読み込み、キャッシュ、ドアを開けた先に何が見えるか——どれも「背景がただのグラデーションだった」間は、そもそも問題になりようがありませんでした。同じ検証環境だけでテストしていると気づけない不具合がある、ということも今回の音声バグで痛感しました。

背景やオブジェクトの位置調整では、スクリーンショットを撮ってグリッドを重ねて測り、合成画像を作って確認してもらい、ズレを直す、というやり取りを何周も繰り返しました。この「言葉で位置を指示する」というやり方の限界に、次回はついに手を打つことになります。


次回:第4話「配置調整、指示するより自分でやった方が早くない?から生まれた専用ツールの話」

コメント

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