こんにちは、Unityエンジニアのオオバです。

お悩みさん
お悩みさん
  • エディタでは動くのに実機だけ「未定義」エラーが出る
  • データは正しく入っているはずなのに見つからないと言われる
  • Addressablesのリモート配信とアプリ同梱データの関係がよく分からない
  • オオバ
    オオバ
    本記事ではこれらの悩みを解決します。

    エディタでは普通にバトルに入れる。

    なのに、iOS の実機だけ「敵ID が未定義」のエラーで止まってしまう。

    先日、Unity でゲームを開発していて、この現象に出会いました。

    「データはちゃんと入っているのに、なんで見つからないの?」

    実機だけで起きる不具合って、エディタで再現しない分、手がかりが少なくて焦りますよね。

    ということで本記事では、原因の正体と対処、そして同じ事故を繰り返さないために入れた工夫をお届けします。

    アプリ同梱の敵定義が古く、リモート配信のクエストだけが先に新しくなっていた

    先に結論です。

    敵の定義(パラメータの一覧)は「アプリ同梱」、クエストの敵配置は Addressables の「リモート配信」と、配信経路が別々になっていました。

    新しい敵を追加したクエストだけがリモートで先に届き、古いアプリの中にはその敵の定義が無かったわけです。

    対処は、最新のブランチでアプリを再ビルドすること。

    データ側には手を入れていません。

    この記事のポイント
    • 敵定義はアプリ同梱・クエストはリモート配信と配信経路が分かれていた
    • エディタは両方とも最新を見るので食い違わない
    • 実機ではアプリのビルド時点の敵定義とリモートの最新クエストが組み合わさる
    • 実機だけの未定義系はアプリのビルド時点と同梱データの更新コミットを比べる
    • 参照し合うデータは配信経路をそろえる

    起きたこと

    症状はシンプルです。

    エディタで再現しないので、ブレークポイントを置いて追いかけることもできません。

    手元にあるのは実機のログだけ。

    正直、最初は「データの入力ミスかな?」と思いました。

    ところがエディタで動いている以上、クエストのデータも敵のデータも、プロジェクトの中では正しくそろっています。

    データが壊れているわけでもない。

    それなのに実機では見つからない、という状況でした。

    原因:配信経路の違うデータが食い違っていた

    原因を探るために、まず「敵の定義」と「クエストの敵配置」が、それぞれどうやってアプリに届いているかを整理しました。

    ここがポイントでした。

    2つのデータは参照し合っているのに、届く経路が違うんですよね。

    エディタでは食い違わない

    エディタで遊ぶときは、どちらのデータもプロジェクト内の最新のアセットを見ます。

    敵の定義もクエストも同じ時点のものなので、ずれようがありません。

    エディタで再現しなかったのは、この仕組みのせいです。

    実機では「ビルド時点」と「最新」が組み合わさる

    実機は事情が違います。

    この状態で、新しい敵を使うクエストがリモートに配信されました。

    クエストのデータは新しい敵の ID を指しています。

    ところが、実機のアプリに入っている敵の定義は、その敵が追加される前のもの。

    結果として「その敵 ID は知りません」となっていました。

    飲食店で例えると、厨房のレシピ本(アプリ同梱)は開店時に配られたまま、本部から毎日届く「今日のおすすめ」(リモート配信)だけが更新されている状態です。

    おすすめに新メニューが載っても、レシピ本にその料理が無ければ厨房は作れません。

    つまり、片方だけが新しくなると、もう片方が追いつくまで壊れ続けるということ。

    対処:最新のブランチでアプリを再ビルド

    原因が分かれば、対処はあっさりしたものでした。

    最新のブランチでアプリを再ビルドして、同梱される敵の定義を新しくしただけです。

    クエスト側のデータは正しいので、触る必要はありません。

    アプリ側の敵定義が新しい敵を知ってさえいれば、クエストはそのまま動きます。

    「データがおかしい」と思い込んでデータを直しにいくと、正しいデータを壊すことになりかねません。

    なぜなら、エディタで動いているという事実が、データ自体は正しいことを示しているから。

    再発防止1:実機だけの「未定義」は2つの時点を比べる

    今回の経験から、実機だけで起きる「未定義」系のエラーに出会ったら、まず次の2つを比べることにしました。

    同梱データの更新がアプリのビルドより後なら、実機のアプリはその更新を知りません。

    そこにリモート配信のデータが新しい ID を持ち込むと、今回と同じことが起きます。

    この比較は、コードを1行も読まずにできるのがありがたいところ。

    ビルドの日時と Git の履歴を並べるだけなので、真っ先に確認する項目にしています。

    再発防止2:ログだけで原因が分かるエラー文にする

    もう1つ手を入れたのが、エラー文そのものです。

    「未定義です」と出るだけだと、「どのクエストで」「アプリが何を知っているのか」が分からず、ログを見た人が推理するしかありません。

    そこで、エラー文に次の情報を入れるようにしました。

    定義済みの一覧が出ていれば、問題の ID が一覧に無いことがひと目で分かります。

    そこから「アプリが古いのでは?」という発想まで、すぐにたどり着ける。

    さらに対処方法まで書いておけば、自分以外のメンバーがログを見ても動けます。

    実機の不具合は、エディタのようにその場で中身を覗けません。

    だからこそ、ログを読んだ人が次の一手まで決められるエラー文にしておく価値があります。

    補足:参照し合うデータは配信経路をそろえる

    根本的な話をすると、今回の原因は設計にあります。

    正本が別のリポジトリにあり、配信経路も別のデータ同士が、お互いを参照していました。

    この形だと、片方だけが更新される瞬間が必ず生まれます。

    再ビルドで直しても、次に新しい敵を追加したときにまた同じことが起きかねません。

    避ける方法は、参照し合うデータの配信経路をそろえることです。

    両方リモートなら、敵の定義とクエストを同じタイミングで届けられます。

    両方同梱なら、アプリを更新しない限りどちらも変わらないので、食い違いは起きません。

    「このデータはどこから届くのか」は、作っている最中はあまり意識しないですよね。

    データ同士の参照を足すときは、参照の向きと配信経路をセットで見ておくと安心です。

    Addressables のグループ設定まわりでハマった話は、こちらにもまとめています。

    👉 【Addressables】AssetGroupにアセットを追加したのにロード失敗する件

    まとめ

    実機だけで「未定義」エラーが出たときは、データの中身より先に、データの届き方を疑ってみてください。

    今回のポイントをまとめます。

    エディタで動くのに実機で動かない不具合は、誰もが一度はぶつかる壁です。

    あなただけではありません。

    配信経路という視点を1つ持っておくだけで、次に出会ったときの調査はぐっと短くなるはずです。

    オススメ記事
    検証環境