UnityでSceneビューとPlayモードのUI表示が違ったときに確認したこと
Unityでスマートフォン向けゲームのUIを制作中、SceneビューとPlayモードで配置や大きさが変わる問題が発生しました。コードによる再生成、RectTransform、Layout Group、Canvas Scalerなどを順番に確認した記録です。
Unityで制作しているスマートフォン向けゲーム「おはじきバトル(仮)」では、ホーム画面やキャラクター画面、クエスト画面などのUIを作り直しています。
その作業中、Sceneビューで整えたはずのUIが、Playモードにすると違う位置や大きさで表示される問題が発生しました。
Sceneビューでは正しく見えていても、ゲームを再生した瞬間にレイアウトが変わるため、Inspectorで調整しても修正内容が反映されているのか分かりにくい状態でした。
この記事では、実際に確認したポイントと、今後同じ問題が起きたときの切り分け方を記録します。
発生していた問題
確認できた主な現象は、次のとおりです。
- SceneビューとPlayモードでUIの位置が異なる
- Sceneビューで変更したサイズが、Play開始後に元へ戻る
- 一部のUIが想定より大きく表示される
- ボタンやカードの間隔がPlayモードで変わる
- RectTransformのHeightを直接変更できないことがある
- Android実機では、さらに表示位置がずれる
一つの原因だけで発生しているとは限らず、複数の設定やスクリプトが同時に影響している可能性がありました。
最初に確認したこと
まず、Sceneビューで編集しているオブジェクトと、Playモードで表示されているオブジェクトが本当に同じものかを確認しました。
Playモード中にHierarchyを見ると、起動時のスクリプトによって新しいUIオブジェクトが生成されている場合があります。
この状態では、Scene上に置いたUIを修正しても、Play開始時に別のUIが生成されたり、設定値が上書きされたりします。
確認するときは、次の点を見ました。
- Play開始後にHierarchyのオブジェクト数が増えていないか
- 同じ名前のCanvasやPanelが複数存在していないか
InstantiateやUI生成用メソッドが実行されていないかAwake、Start、OnEnableで位置やサイズを変更していないか- Prefabを生成し直すEditorスクリプトが動いていないか
今回のプロジェクトでは、もともと画面UIの多くをC#から生成していました。
そのため、Scene上で手動調整した内容よりも、Play開始時に実行されるコードの設定が優先される箇所がありました。
コードによるUIの再生成を確認する
UIをコードで生成する構成では、ボタンやテキスト、画像などをまとめて作成できます。
一方で、次のような処理が残っていると、Sceneビューで調整した内容がPlayモードで上書きされます。
rectTransform.anchoredPosition = new Vector2(0f, -120f);
rectTransform.sizeDelta = new Vector2(900f, 180f);
Prefabへ移行した後も、以前の生成処理や配置処理が残っていると、同じ問題が続くことがあります。
そこで、UIに関係するスクリプトから、次の文字列を中心に検索しました。
Instantiate
anchoredPosition
sizeDelta
SetParent
SetActive
AddComponent
特に、AwakeやStartから呼ばれているメソッドは、Sceneビューでは実行されず、Play開始後にだけ影響するため注意が必要です。
RectTransformのアンカーを確認する
コードで上書きされていない場合は、RectTransformの設定を確認します。
UnityのUIは、単純なX座標・Y座標だけではなく、親オブジェクトに対するアンカーを基準に配置されます。
アンカーが左右や上下に広がるStretch設定になっていると、InspectorにはWidthやHeightではなく、Left、Right、Top、Bottomが表示されることがあります。
この場合は、子要素の幅や高さが親要素のサイズから自動的に決まるため、Heightを直接変更できないように見えます。
確認した項目は次のとおりです。
- Anchor MinとAnchor Maxが同じ位置になっているか
- 横方向または縦方向にStretchしていないか
- Pivotが意図した位置に設定されているか
- 親のRectTransformが想定したサイズになっているか
sizeDeltaの値が別の処理から変更されていないか
固定サイズにしたいUIでは、Anchor MinとAnchor Maxを同じ位置にそろえます。
画面幅に合わせて伸縮させたい背景やパネルでは、Stretchを利用し、LeftやRightなどの余白を調整します。
すべてを固定サイズにするのではなく、UIの役割に応じてアンカーを使い分ける必要があります。
Layout Groupの影響を確認する
RectTransformの値を変更しても元へ戻る場合は、親オブジェクトにLayout Groupが付いていないかを確認します。
対象になりやすいコンポーネントは次のとおりです。
- Vertical Layout Group
- Horizontal Layout Group
- Grid Layout Group
- Content Size Fitter
- Aspect Ratio Fitter
- Layout Element
Layout Groupが付いていると、子オブジェクトの位置やサイズは親によって自動的に計算されます。
そのため、子オブジェクトのHeightを直接変更しても、レイアウトが再計算されたタイミングで別の値に戻ることがあります。
クエスト一覧やキャラクター一覧のように、同じ形のカードを縦や横に並べる画面ではLayout Groupが便利です。
ただし、カードごとに個別のサイズを設定したい場合は、Layout ElementのPreferred WidthやPreferred Heightを使うか、親側のChild Control Sizeなどを見直す必要があります。
Canvas Scalerを確認する
SceneビューとGameビューで大きさが異なる場合は、Canvas Scalerも確認しました。
スマートフォン向けUIでは、Canvas Scalerを次のように設定しています。
UI Scale Mode: Scale With Screen Size
Reference Resolution: 基準にする画面解像度
Screen Match Mode: Match Width Or Height
Matchの値によって、横幅を優先するか、縦幅を優先するかが変わります。
縦長端末を前提に作っていても、Gameビューの解像度やアスペクト比が違えば、UIの見え方も変わります。
Sceneビューだけで判断せず、Gameビューで実際に使用する解像度を選び、複数のアスペクト比で確認することが重要でした。
Playモード中の変更は保存されない
Unityでは、Playモード中にInspectorから変更した値は、Playモードを終了すると基本的に元へ戻ります。
表示を確認しながら調整できるため便利ですが、Playモード中に直したつもりになり、その変更が消えてしまうことがありました。
調整するときは、次の流れにすると混乱を減らせます。
- Playモードで適切な値を探す
- 必要な値をメモする
- Playモードを終了する
- SceneまたはPrefabへ同じ値を設定する
- もう一度Playモードで確認する
Prefabを編集している場合は、変更先がScene上のインスタンスなのか、元のPrefabなのかも確認します。
今回の修正方針
今回のUI改修では、見た目と配置をSceneおよびPrefabで管理し、C#はデータ設定と画面遷移を中心に担当する構成へ移行しています。
役割は次のように分けます。
Scene・Prefabで管理するもの
- UIの位置と大きさ
- アンカーとPivot
- 画像や背景
- ボタンの配置
- カード同士の間隔
- フォントサイズや文字色
C#で管理するもの
- キャラクターやクエストのデータ表示
- ボタンを押したときの処理
- 画面の切り替え
- 所持数やステータスの更新
- 一覧に表示する要素の生成
完全にコード生成をなくすのではなく、繰り返し表示するカードなどはPrefabを元に生成します。
見た目そのものをコードへ直接書かず、Prefab側で調整できるようにすることが目的です。
問題を切り分ける確認順
今回の経験から、同じ問題が起きたときは次の順番で確認すると分かりやすいと考えています。
- Play開始後に別のUIが生成されていないか
- スクリプトが位置やサイズを上書きしていないか
- RectTransformのアンカーがStretchになっていないか
- 親のLayout Groupが子のサイズを制御していないか
- Content Size Fitterなどが再計算していないか
- Canvas ScalerとGameビューの解像度が適切か
- Playモード中だけ変更していないか
- PrefabとScene上のインスタンスのどちらを編集しているか
最初からすべての数値を調整し直すよりも、「誰がこのRectTransformの値を決めているのか」を探すほうが原因へ近づきやすくなりました。
現在の状況
コードだけで生成していたUIをuGUIとPrefabへ移行したことで、Scene上で見た目を確認しながら調整できる範囲は増えました。
一方で、Android実機では端末の縦横比やステータスバー、下部のナビゲーション領域なども影響します。
そのため、SceneビューとPlayモードが一致しただけで完了とはせず、最後は実機でも確認する方針です。
現在は、ホーム画面、キャラクター画面、クエスト画面を順番に調整しています。今後は、画面ごとの修正結果や、実機表示で確認できた変化も記録していく予定です。
まとめ
SceneビューとPlayモードでUI表示が異なる場合、RectTransformの数値だけを直しても解決しないことがあります。
今回、特に重要だと感じたのは次の点です。
- Play開始時にUIが再生成・再配置されていないか確認する
- RectTransformのアンカーと親子関係を確認する
- Layout GroupやContent Size Fitterによる自動制御を確認する
- Canvas Scalerと確認用解像度をそろえる
- 見た目はScene・Prefab、動作はC#という役割分担を意識する
- 最後はAndroid実機で確認する
UIが意図しない位置へ移動したときは、表示された結果だけでなく、その値を設定しているスクリプトやレイアウトコンポーネントまで確認する必要があります。
今後も、実際に発生した問題と修正過程を、同じ問題で困ったときに振り返れる形で残していきます。