Unity WebGLの配列範囲外エラー:回復対象の切替で落ちた原因

ホラーRPG「ヴェイルモート」で、回復対象を選ぶとWebGLが停止した実例。memory access out of boundsを診断版で調べ、IMGUIの描画中に仲間と敵の配列が切り替わる原因を特定した記録です。

Libra

公開 2026年10月20日 ・ 更新 2026年10月24日

この記事の要点3項目

対象選択の途中で、配列の種類が変わっていました。 仲間3人のボタンを描くループが、敵1体の配列を読み始めていました。

残り2つの要点を読む
  • 連続戦闘だけでは再現しませんでした。 開発版の例外情報から、最初の人物が傷薬を使う一操作へ条件を絞りました。
  • 修正後はPC・タッチで各2条件を確認しました。 ゲームの難易度や乱数、メモリ容量は変更していません。
目次7章
検証した環境最終確認 2026年10月20日
  • Unity 6.6(6000.6.0f1)・WebGL / IL2CPP
  • Windows・ChromeでのPC操作と812×375の模擬タッチ
  • 通常版88c4302f・開発診断版edf1b191

書いてあるのは、この環境で実際に試した結果です。ツールの仕様や料金は変わるので、重要な判断の前には公式の情報も確認してください。

回復ボタンを押した直後、仲間の配列を読んでいた処理が敵の配列へ切り替わっていました。 ホラーRPG「ヴェイルモート」(検証当時の題名は「葬約の国」)の長い遠征で起きた停止は、音や敵の枚数を減らして直す問題ではありませんでした。

これは、UnityのIMGUIで作った戦闘画面を直した制作記録です。ゲーム一式の作り方ではなく、実際の失敗、原因を絞った順序、修正した範囲を残します。

遠征の途中で、WebGLの実行が止まった

最初は水路の主との戦闘中でした。PCでは15ターン目、模擬タッチでは5ターン目に、次の表示が出ました。保存を観測する処理にも応答しなくなります。

通常版で出たエラーエラー
Uncaught exception from main loop:
RuntimeError: memory access out of bounds
Halting program.

同じブラウザーの中断保存から再開すると、主を倒せました。帰還して宿泊もできます。再開すれば動くことと、長い遠征を止まらず遊べることは別でした。

私はまず、音の有無と保存の反復を切り分けました。どちらも停止を再現できず、例外が起きた場所を調べる方へ進みました。

実施した切り分け結果と、分からないこと
音ありの合成戦闘を70ターン停止を再現しなかった。音に問題がないとまでは言えない
音なしの合成戦闘を70ターンこちらも停止しなかった。音を切れば解決するという根拠にならない
通常UIで保存取込200回、その後70ターン例外0。保存回数だけでも再現しなかった
別出力の開発版で、同じ実保存から水路遠征画面描画のIndexOutOfRangeExceptionを取得できた

連続戦闘の検査では通常攻撃を選び続けていました。後で分かった原因の操作が、その中にありません。

開発版では、戦闘画面の配列範囲外と分かった

公開候補を上書きせず、Development BuildとFullWithStacktraceを使った診断版を別フォルダーへ出力しました。同じ実冒険の保存ファイルを標準の取込操作で読み、水路へ向かいました。

診断版では帰還・宿泊まで操作できましたが、コンソールには次の例外が残りました。クリアできたことだけを成功にすると、このエラーを見落とします。

診断版で取得した呼出元エラー
IndexOutOfRangeException: Index was outside the bounds of the array.
  at Hollow.Runtime.GameView.BattleScreen ()
  at Hollow.Runtime.GameView.OnGUI ()

PC用のBattleScreenを読むと、対象ボタンの件数はループの前に決めている一方、対象が仲間か敵かは毎回判定していました。タッチ用のCompactBattleにも同じ処理がありました。

ボタンを押した、その描画の途中で行動が変わっていた

戦闘では3人分の指示を順に選びます。傷薬の対象を割り当てるAssignは、次の人物へ進む時に行動をattackへ戻していました。

同じループの中で起きた順序状態
傷薬の対象ボタンを用意する仲間3人なので、反復回数は3
仲間0のボタンを押すAssignが次の人物へ進め、行動をattackに変更
続きのボタンを描く行動が攻撃なので、敵の配列を参照
敵1を読む敵は1体。存在する添字は0だけなので範囲外

最初に決めた件数は3のままです。後から読む配列だけが敵側へ変わる。この組み合わせが問題でした。

敵1体との戦闘で、リオからリオへの傷薬を予約し、次のセナの指示へ進んだ修正後の画面
修正後の通常版。回復はまだ予約段階で、次の人物には敵1体の攻撃対象を表示する。この切替の途中で例外が起きていた。

以前の回復表示の検査は、最後の人物が仲間0へ回復する条件でした。最後の人物の指示が揃うと保存処理へ進み、その場で次の人物の攻撃へは切り替わりません。回復できるかを確かめていても、今回の境界は覆えていませんでした。

対象の種類を固定し、選択したら描画関数から戻す

PCとタッチの両方で、仲間向けか、蘇生向けかをループの最初に固定しました。また、対象ボタンを押したらその画面の描画関数から戻し、残りのボタンを変更後の状態で読み進めないようにしました。

次は実装の構造を短くした抜粋です。ゲーム本体の対象名・座標・Assignは省略しているため、単独で動く完成コードではありません。

bool allies = AllyAction;
bool reviving = action == "revive";
int count = allies ? State.party.Length : battle.enemies.Length;

for (int i = 0; i < count; i++)
{
    // 対象名や有効状態も、固定した allies / reviving で決める。
    // ボタン操作で Assign(i) が行動を変えても、残りへ進まない。
    if (DrawTargetButton(i, allies, reviving))
        return;
}

単に添字を配列の末尾へ丸める修正にはしませんでした。そうすると、存在しない敵の代わりに別の敵を表示し、選択の不整合を隠してしまいます。

一操作で再現する検査に変えた

長い遠征を繰り返す代わりに、敵1体・仲間3人・傷薬2個の合成入口を用意しました。保存ファイルを通常UIで読み、最初の人物から仲間0へ傷薬を予約します。

修正前の開発版では、PCのBattleScreen、模擬タッチのCompactBattleで同じ例外を再現しました。修正後の通常版では、最初の人物と途中の人物の2条件を、両方の操作方式で確認しました。

修正後に確認したもの結果
最初の人物からの傷薬対象選択PC・模擬タッチとも例外0
途中の人物からの傷薬対象選択PC・模擬タッチとも例外0
指示を全員分選んだ後の保存2ターン目、傷薬1個消費、体力回復を確認
通常ビルド194.57秒、14,893,041バイト、ビルドエラー0

合成入口は、この不具合の再現専用です。ゲームを正規の資源で攻略できる証明には使っていません。難易度、乱数、メモリ容量も、この修正では変えていません。

今回残した再発防止は、最初・途中・最後の対象で、次の入力状態へ移る操作を確かめることです。検査のターン数を増やす前に、どの入力で状態が切り替わるかを見る必要がありました。

文字欠けを実ファイルから調べた例はUnity WebGLの日本語フォントを絞った記録、操作やカメラの作り直しは横スクロールアクションの制作記録へまとめています。

同じゲームの画像取込と配信対象を見直した結果は、WebGLの配信を40.6%削減した記録へまとめました。

よくある質問

よくある質問

memory access out of boundsはメモリ不足という意味ですか?

この表示だけでは原因を決められません。本作では、開発版でIndexOutOfRangeExceptionを取得し、描画中に違う配列を読んでいたことを確認しました。

敵が多い時だけ落ちたのですか?

逆に、敵1体に対して仲間3人分のボタンがある条件で再現しました。最初の人物が仲間0へ傷薬を割り当てると、次の反復で存在しない敵1を読んでいました。

修正後はゲーム全体の動作も保証できましたか?

この検査で確認したのは、PCと模擬タッチで最初・途中の人物から回復対象を選ぶ4条件です。本編全体、性能、実スマホ、人の面白さは別に確認する必要があります。

出典

出典

  1. 01Memory in Unity WebUnity Technologiesヒープの自動拡張とメモリ制約の説明を確認。今回の原因がメモリ不足だと示す資料ではありません。

この記事は役に立ちましたか?

関連記事