こんにちは、Unityエンジニアのオオバです。
エディタでは普通にバトルに入れる。
なのに、iOS の実機だけ「敵ID が未定義」のエラーで止まってしまう。
先日、Unity でゲームを開発していて、この現象に出会いました。
「データはちゃんと入っているのに、なんで見つからないの?」
実機だけで起きる不具合って、エディタで再現しない分、手がかりが少なくて焦りますよね。
ということで本記事では、原因の正体と対処、そして同じ事故を繰り返さないために入れた工夫をお届けします。
アプリ同梱の敵定義が古く、リモート配信のクエストだけが先に新しくなっていた
先に結論です。
敵の定義(パラメータの一覧)は「アプリ同梱」、クエストの敵配置は Addressables の「リモート配信」と、配信経路が別々になっていました。
新しい敵を追加したクエストだけがリモートで先に届き、古いアプリの中にはその敵の定義が無かったわけです。
対処は、最新のブランチでアプリを再ビルドすること。
データ側には手を入れていません。
- 敵定義はアプリ同梱・クエストはリモート配信と配信経路が分かれていた
- エディタは両方とも最新を見るので食い違わない
- 実機ではアプリのビルド時点の敵定義とリモートの最新クエストが組み合わさる
- 実機だけの未定義系はアプリのビルド時点と同梱データの更新コミットを比べる
- 参照し合うデータは配信経路をそろえる
起きたこと
症状はシンプルです。
- iOS の実機で、あるクエストのバトルに入ろうとすると「敵ID が未定義」のエラーになる
- エディタでは同じクエストを問題なく遊べる
エディタで再現しないので、ブレークポイントを置いて追いかけることもできません。
手元にあるのは実機のログだけ。
正直、最初は「データの入力ミスかな?」と思いました。
ところがエディタで動いている以上、クエストのデータも敵のデータも、プロジェクトの中では正しくそろっています。
データが壊れているわけでもない。
それなのに実機では見つからない、という状況でした。
原因:配信経路の違うデータが食い違っていた
原因を探るために、まず「敵の定義」と「クエストの敵配置」が、それぞれどうやってアプリに届いているかを整理しました。
- 敵の定義(パラメータの一覧): シーンから直接参照されているアセット。つまりビルド時にアプリへ同梱される
- クエストの敵配置: Addressables のアセット。リモートから配信される
ここがポイントでした。
2つのデータは参照し合っているのに、届く経路が違うんですよね。
エディタでは食い違わない
エディタで遊ぶときは、どちらのデータもプロジェクト内の最新のアセットを見ます。
敵の定義もクエストも同じ時点のものなので、ずれようがありません。
エディタで再現しなかったのは、この仕組みのせいです。
実機では「ビルド時点」と「最新」が組み合わさる
実機は事情が違います。
- 敵の定義: アプリをビルドした時点のもの(アプリに焼き込まれている)
- クエストの敵配置: リモートにある最新のもの
この状態で、新しい敵を使うクエストがリモートに配信されました。
クエストのデータは新しい敵の ID を指しています。
ところが、実機のアプリに入っている敵の定義は、その敵が追加される前のもの。
結果として「その敵 ID は知りません」となっていました。
飲食店で例えると、厨房のレシピ本(アプリ同梱)は開店時に配られたまま、本部から毎日届く「今日のおすすめ」(リモート配信)だけが更新されている状態です。
おすすめに新メニューが載っても、レシピ本にその料理が無ければ厨房は作れません。
つまり、片方だけが新しくなると、もう片方が追いつくまで壊れ続けるということ。
対処:最新のブランチでアプリを再ビルド
原因が分かれば、対処はあっさりしたものでした。
最新のブランチでアプリを再ビルドして、同梱される敵の定義を新しくしただけです。
クエスト側のデータは正しいので、触る必要はありません。
アプリ側の敵定義が新しい敵を知ってさえいれば、クエストはそのまま動きます。
「データがおかしい」と思い込んでデータを直しにいくと、正しいデータを壊すことになりかねません。
なぜなら、エディタで動いているという事実が、データ自体は正しいことを示しているから。
再発防止1:実機だけの「未定義」は2つの時点を比べる
今回の経験から、実機だけで起きる「未定義」系のエラーに出会ったら、まず次の2つを比べることにしました。
- 実機に入っているアプリが、いつの時点のブランチでビルドされたものか
- アプリ同梱のデータが、最後に更新されたのはどのコミットか
同梱データの更新がアプリのビルドより後なら、実機のアプリはその更新を知りません。
そこにリモート配信のデータが新しい ID を持ち込むと、今回と同じことが起きます。
この比較は、コードを1行も読まずにできるのがありがたいところ。
ビルドの日時と Git の履歴を並べるだけなので、真っ先に確認する項目にしています。
再発防止2:ログだけで原因が分かるエラー文にする
もう1つ手を入れたのが、エラー文そのものです。
「未定義です」と出るだけだと、「どのクエストで」「アプリが何を知っているのか」が分からず、ログを見た人が推理するしかありません。
そこで、エラー文に次の情報を入れるようにしました。
- どのクエストで起きたか(クエストID)
- アプリが知っている敵 ID の一覧(定義済みの ID 一覧)
- 対処方法
定義済みの一覧が出ていれば、問題の ID が一覧に無いことがひと目で分かります。
そこから「アプリが古いのでは?」という発想まで、すぐにたどり着ける。
さらに対処方法まで書いておけば、自分以外のメンバーがログを見ても動けます。
実機の不具合は、エディタのようにその場で中身を覗けません。
だからこそ、ログを読んだ人が次の一手まで決められるエラー文にしておく価値があります。
補足:参照し合うデータは配信経路をそろえる
根本的な話をすると、今回の原因は設計にあります。
正本が別のリポジトリにあり、配信経路も別のデータ同士が、お互いを参照していました。
この形だと、片方だけが更新される瞬間が必ず生まれます。
再ビルドで直しても、次に新しい敵を追加したときにまた同じことが起きかねません。
避ける方法は、参照し合うデータの配信経路をそろえることです。
- 両方ともリモート配信にする
- 両方ともアプリに同梱する
両方リモートなら、敵の定義とクエストを同じタイミングで届けられます。
両方同梱なら、アプリを更新しない限りどちらも変わらないので、食い違いは起きません。
「このデータはどこから届くのか」は、作っている最中はあまり意識しないですよね。
データ同士の参照を足すときは、参照の向きと配信経路をセットで見ておくと安心です。
Addressables のグループ設定まわりでハマった話は、こちらにもまとめています。
👉 【Addressables】AssetGroupにアセットを追加したのにロード失敗する件
まとめ
実機だけで「未定義」エラーが出たときは、データの中身より先に、データの届き方を疑ってみてください。
今回のポイントをまとめます。
- 敵の定義はアプリ同梱、クエストは Addressables のリモート配信と、配信経路が分かれていた
- エディタは両方とも最新を見るので食い違わず、再現しない
- 実機では「ビルド時点の敵定義」と「リモートの最新クエスト」が組み合わさり、新しい敵が未定義になった
- 対処は最新のブランチでのアプリ再ビルド
- 実機だけの未定義系は「アプリのビルド時点」と「同梱データの更新コミット」を比べる
- エラー文にクエストID・定義済みの ID 一覧・対処方法を入れて、ログだけで原因が分かるようにする
- 参照し合うデータは、両方リモートか両方同梱にそろえる
エディタで動くのに実機で動かない不具合は、誰もが一度はぶつかる壁です。
あなただけではありません。
配信経路という視点を1つ持っておくだけで、次に出会ったときの調査はぐっと短くなるはずです。

筆者のXをフォローしよう
- Unity 6000.3 / Addressables / iOS






