個人開発でAIとゲームを作って詰まったところ──公開までに直した3つ
AI画像生成と3D化ツールでゲームキャラクター15体を作った過程で、実際に起きた3つの詰まりを実測ログとともに記録する。file://直開きでモデルが読み込めなかった件、AIツールの英語ファイル名で「鬼」に誤配置された件、キャラクター全員が横を向いて歩いていた向きバグの3つ。

目次
AIにコードを書かせてゲームを個人開発すると、「動くものはすぐできる」一方で、AIが生成した3Dモデルや画像素材をゲームに組み込む工程では、コード生成とは別種の詰まりが出る。この記事は、自作のブラウザゲーム「百鬼夜行大合戦」でキャラクター15体を3D化・組み込みした際に実際に起きた3つの詰まりを、当時の開発記録から実測値つきで書く。デザインの作り方自体は個人開発でデザインをAIに任せた手順に書いたので、この記事はそこで起きた「うまくいかなかった側」の記録になる。
3行まとめ
file://でHTMLを直接開くとブラウザのCORS制限でGLB・画像が全部ブロックされる。ローカルサーバを立てるまで気づかなかった- image-to-3Dツールが英語で自動で付けるファイル名は取り違えやすい。「ogre monk」という説明が「鬼」に誤マッチして配置され、目視で気づいて直した
- AI画像生成した参照画像の向きと、ゲーム側コードが前提にしていた正面方向がズレていて、キャラクター15体全員が横を向いて歩くバグになっていた
詰まり1: file://直開きでGLB・画像が全部ブロックされた
HTMLファイル1枚で動くブラウザゲームなので、開発中はローカルのHTMLファイルをブラウザで直接開いて(file:///path/to/index.html)動作確認していた。ところが3DモデルのGLBファイルをゲームに組み込んだ段階で、キャラクターが表示されなくなった。
原因はブラウザのCORS制限だった。file://スキームで開いたページから同じくローカルのfile://パスのGLBファイルや画像をfetchで読み込もうとすると、ブラウザはこれをクロスオリジンの読み込みとして扱いブロックする。HTTPサーバー経由でファイルを配信していないと、ローカルの別ファイルへのアクセスがそもそも通らない。
直し方は単純で、python3 -m http.serverでローカルにHTTPサーバーを立て、http://localhost:8123/index.htmlとしてアクセスするようにした。http.serverはオプションを付けなければポート8000で待ち受けるが、今回はポートを明示的に指定して起動スクリプトに固定した。開発中も本番のデプロイ後と同じ条件で確認できるよう、ダブルクリックでサーバー起動とブラウザ表示を一度に行う起動スクリプトを1つ用意して、以降の動作確認はすべてそちら経由にした。デプロイ後は通常のHTTPで配信されるため、この問題自体は発生しない。開発中のfile://直開きだけで踏む罠だった。
MDNのCORSエラー解説を確認すると、この挙動は最近のブラウザの仕様変更が原因だと分かる。以前はローカルの同一ディレクトリ・サブディレクトリ内のファイル同士は「同一オリジン」として扱われ、file://直開きでも周辺ファイルの読み込みがブロックされることはなかった。しかしこの挙動にはセキュリティ上の問題があり(Mozillaのセキュリティ勧告CVE-2019-11730で指摘されている)、Firefox・Chromeを含む主要ブラウザは現在、ローカルファイルをデフォルトで「不透明オリジン(opaque origin)」として扱うよう変更している。つまり今回踏んだCORSブロックは自分のコードやゲームエンジンの不具合ではなく、ブラウザ側が数年前に入れたセキュリティ強化の副作用で、ローカル開発者はfile://直開きをやめてローカルサーバーを立てることが公式にも推奨されている。
このCORSの制限は、後で作ったアイコン自動生成のスクリプトにも影響していて、そちらもPlaywrightでページを開く前に同じ理由でローカルサーバーを起動する処理を入れている。
詰まり2: AIツールの英語ファイル名で「鬼」に誤配置された
image-to-3DツールからダウンロードしたGLBファイルは、日本語のキャラクターkey名ではなく、ツール側が画像を見て推測した英語の説明的な名前でダウンロードされる。取り込みスクリプトはこの英語名からキャラクターを推測して自動配置する作りにしていたが、最初にまとめて3体を取り込んだ際、「大入道」(巨大な坊主の妖怪)の3DモデルにTripoが付けたファイル名が「ogre monk」で、これが「鬼」(oni)というキーワードに部分一致し、誤って鬼のモデルとして配置されてしまった。
気づいたきっかけは、取り込み後に自動生成されたアイコン画像を目で確認したことだった。鬼のアイコンのはずが坊主頭の巨大なキャラクターが表示されていて、そこで初めて誤配置に気づいた。名前の完全一致だけに頼るとこの手の取り違えは防げないため、以降は取り込みのたびに、元にした参照画像とアイコンの見た目を目視で突き合わせる工程を追加した。別の回では「samurai warrior」という似た名前の説明が2体分あり、名前だけでは判別できず3Dレンダを直接見て「薙刀僧」「足軽槍」と同定した例もある。
これは自動化した工程の中に人間の目視確認を必ず1つ残しておく必要がある、という個人開発でも当てはまる教訓だった。取り込みスクリプト自体の仕組みはデザインをAIに任せた手順の記事に書いている。
詰まり3: キャラクター全員が横を向いて歩いていた
15体のGLBモデルをすべて取り込み終えた後、実機で動作確認すると、キャラクターが本来進むべき方向とは90度ずれた向きで歩いていることに気づいた。
原因を切り分けると、ゲーム側のコードは各モデルの正面方向を「+Z軸」だと仮定して、自軍と敵軍で±90度の回転を掛ける実装になっていた。一方でTripoが出力する3Dモデルは、15体すべてが「+X軸」を正面として出力されていた。この前提のズレが、全キャラクター共通の90度の向きのズレとして出ていた。
確認は、キャラクターを4方向から撮影したレンダリング画像を並べて、実際にどちらが正面なのかを目で確認する形で行った。原因が特定できてからの修正自体は、自軍を0度、敵軍を180度の回転に変更するだけの1行修正で済んだが、そこにたどり着くまでは「コードのどこかにバグがある」と思って回転計算のロジックを疑っていた時間の方が長かった。実際の原因はコード側ではなく、3D化ツールの出力する座標系についての前提が違っていただけだった。
このズレを後からKhronos Groupが公開しているglTF 2.0の公式仕様書で確認すると、glTFフォーマット自体は右手座標系を採用し、「+Yを上、+Zを前面とし、アセットの正面は+Z軸を向く」ことを仕様として明記している(3.4節 Coordinate System and Units)。つまりゲーム側コードが最初に仮定していた「+Z軸が正面」は、glTFフォーマットの規定そのものと一致していたことになる。一方でTripoが実際に書き出した15体分のGLBは、すべて+X軸を正面として出力されていた。仕様上の既定は+Z前面であるにもかかわらず、書き出されたモデルはそれとは異なる軸を向いていたわけで、ズレの原因はゲーム側の座標系の理解ではなく、書き出し側の出力が仕様の既定と揃っていなかった点にあったと言える。
この修正と同じタイミングで、キャラクターの身長がスケール値の2乗に比例して大きくなってしまうバグ(大入道が画面を覆うほど巨大化する)と、HPバーが身長と一緒に浮き上がってしまうバグも見つかっている。どちらも「モデルのローカル座標に外側のスケールが二重に掛かっている」という同系統の原因で、3Dモデルをコードから動的にスケーリングする実装では、この手のズレが起きやすいのだと分かった。
番外: エクスポート設定を忘れて1体だけポリゴン数が桁違いになった
3つには数えていないが、もう1つ実際に起きた話を書いておく。image-to-3Dツールでモデルを書き出す際、ローポリ設定を選ばずにエクスポートしてしまった構造物(桜・岩・ワープの床)が、他のキャラクター(1体あたりポリゴン数約4,900前後)の400倍近いポリゴン数で出力されていたことがあった。同時に50体近く表示するゲームでこの1体だけ極端に重いと、全体のフレームレートに影響する。これは取り込みスクリプトのエラーにも現れず、実際にゲームを動かして重さを感じてから初めて発覚した。直し方はエクスポート設定を選び直して出し直すだけだが、「エクスポート時に毎回設定を確認する」というチェック項目が1つ増えた。
4つの詰まりを表で並べる
「番外」も含めた4件を、症状・原因・気づいた方法・直し方で並べ直すと次のようになる。
| 詰まり | 症状 | 原因 | 気づいた方法 | 直し方 |
|---|---|---|---|---|
| 1. CORSブロック | file://直開きでGLB・画像が表示されない |
ブラウザがローカルの別file://パスへのfetchをクロスオリジン扱いでブロック |
3Dモデル組み込み後に画面が真っ黒になった | python3 -m http.serverでローカルHTTPサーバーを起動してhttp://localhost経由に統一 |
| 2. ファイル名誤配置 | 「大入道」のモデルが「鬼」として配置される | image-to-3Dツールが付ける英語名「ogre monk」がoniに部分一致 |
自動生成したアイコンを目視確認 | 名前の完全一致に頼らず、取り込みのたびに参照画像とレンダ結果を目視で突き合わせる工程を追加 |
| 3. 向きバグ | キャラクター15体全員が90度ズレた向きで歩く | ゲーム側は正面を+Z軸と仮定、Tripo出力は+X軸が正面という前提の食い違い | 4方向レンダを並べて目視確認 | 自軍0度・敵軍180度の回転指定に1行修正 |
| 番外. ポリゴン数超過 | 特定のオブジェクト1体だけ極端に重い | エクスポート時にローポリ設定を選び忘れ、他キャラの約400倍のポリゴン数で出力 | 取り込みスクリプトはエラーを出さず、実際にゲームを動かして重さで気づいた | エクスポート設定を選び直して出し直し。「毎回エクスポート設定を確認する」を工程に追加 |
(表の内容はすべて本文中に既出の実測記録の並べ替えで、新たに計測した数値はない。)
3つに共通していたこと
3つの詰まりに共通していたのは、いずれも「AIが生成したコードやモデル単体」の問題ではなく、AIが作ったものと、それを動かす環境・別のAIツールの出力・自分が書いた前提との組み合わせで起きていたことだ。CORSはブラウザの仕様、ファイル名の誤マッチはツールの命名規則、向きのズレは3D化ツールの座標系の話で、どれもコードを読むだけでは気づけず、実際にブラウザで動かし、目で見て初めて分かるものだった。個人開発でAIにコードや素材を作らせる場合でも、最後に自分の目と手で動かして確認する工程は省略できないというのが、この3つから得た実感だ。
ゲームバランスの調整では、この「目視」の代わりにbotの自動プレイを使って数値で判断した工程もある。そちらはゲームバランスをAIのbotに240回遊ばせて計測した記事に別でまとめている。
この記事1本だけで一般化できないこと
- ここに書いた4件は、image-to-3Dツール1種類(Tripo)とブラウザ実行のゲームエンジン構成という、特定の組み合わせで起きたものである。 別のimage-to-3Dツールや別のゲームエンジン(Unity・Unreal等)を使った場合に、同じ種類の詰まり(座標系の前提違いなど)が同じ頻度で起きるかどうかは確認していない。
- 「+X軸が正面」というTripoの出力実態は、この15体の実測から逆算した観測である。 glTF 2.0フォーマット自体の公式仕様(+Zが正面)はKhronos Groupの仕様書で確認したが、Tripo側が「なぜ+X軸で出力するのか」を明記した公式ドキュメントは本稿では見つかっていない。ツール側の既定仕様なのか、モデルの作り方(メッシュのモデリング時点の向き)に起因する結果なのかは切り分けられていない。別バージョンのTripoや別の書き出し設定では変わる可能性がある。
- ポリゴン数「約4,900前後」「400倍近い」という数字は、当時の作業記録からの記載であり、この記事のために数え直したものではない。
- 本稿執筆時点(2026年8月27日)で、
https://hyakki-taisen.vercel.appが実際に稼働していることはcurlで確認したが、ここに記載した4つの不具合が現在のバージョンにまだ残っているか・すでに直っているかは、この記事では区別していない。 いずれも公開前の開発段階で修正済みの過去の記録として書いている。
出典・参照資料
AIニュースの解説を動画でも
YouTubeでは注目ニュースの背景を解説し、Xでは新着記事をお知らせしています。
コメント
まだコメントはありません。最初のコメントを書いてみませんか?
AIについて聞きたいことはありますか?
質問箱で無料で受け付けています。回答は公開され、他の方の参考にもなります。
質問箱を見る →新しい記事をメールで受け取る
AIの新しい発表を、出典付きで整理して届けます。