Unityのコード生成UIをuGUIとPrefabへ移行した記録
Play中にしか確認できなかったスマホゲームのUIを、Scene上で調整できるuGUIとPrefab中心の構成へ移行しました。移行を決めた理由、作業の流れ、自動再生成で起きた問題、今後の改善点をまとめます。
Unityで制作中のスマートフォン向けゲーム「おはじきバトル」では、これまでメニュー画面のUIを主にC#コードから生成していました。
コードだけで画面を作る方法は、同じ構造を自動生成できるという利点があります。一方で、細かな位置や大きさを調整するたびにPlayモードで確認する必要があり、画面数が増えるにつれて作業しにくさを感じるようになりました。
さらにAndroid実機で確認すると、クエストカードが上部ステータスの裏へ入り込む、下部タブアイコンの縁が切れるといった問題も見つかりました。
そこで、見た目と配置をUnityのSceneおよびPrefabで管理し、データと動作をC#で担当する構成へ移行することにしました。
この記事では、コード生成中心のUIから uGUI + Prefab へ移行した理由、実際の作業方針、移行中に発生した問題、現在の状態をまとめます。
移行前のUI構成
移行前は、起動時にスクリプトからUIオブジェクトを作成していました。
画面に必要なパネル、画像、テキスト、ボタンなどをコードで生成し、座標やサイズも数値で指定する構成です。
イメージとしては、次の処理をスクリプトがまとめて担当していました。
Canvasを用意する
↓
背景とパネルを生成する
↓
画像とテキストを配置する
↓
ボタンへ処理を登録する
↓
データを読み込んで表示する
この方法でも画面は作れますが、Sceneを開いただけでは完成状態を確認できません。
Playモードを開始して、コードが実行されたあとに初めてUIが表示される状態でした。
コード生成UIで困ったこと
細かな調整に時間がかかる
例えば、キャラクター名を少し上へ移動するだけでも、コード内の座標を探して数値を変更し、Playモードで確認する必要があります。
コードを修正
↓
Playモードを開始
↓
対象画面へ移動
↓
位置を確認
↓
Playモードを停止
↓
再びコードを修正
数ピクセル単位の調整でも、この手順を繰り返します。
UI全体の大枠はコードで作れても、文字、アイコン、余白、枠線などを実機に合わせて調整する作業とは相性がよくありませんでした。
Play中の変更が保存されない
Playモード中はInspectorからRectTransformを変更できます。
しかし、その変更はPlayモードを停止すると元へ戻ります。よい位置を見つけても、数値を記録してコードへ反映しなければ残りません。
調整したつもりでも保存されていなかった、ということが起きやすい状態でした。
コードの役割が増えすぎる
本来、画面へ表示するランク、スタミナ、ゴールド、キャラクター情報などは、スクリプトから更新する必要があります。
しかし、配置までコードへ集めると、ひとつのスクリプトが次の役割をすべて持つことになります。
- UIオブジェクトの生成
- 座標とサイズの指定
- 画像やフォントの設定
- ボタンイベントの登録
- セーブデータの読み込み
- 表示内容の更新
- 画面の切り替え
画面が増えるほどコードが長くなり、どこを修正すればよいのか分かりにくくなります。
uGUIとPrefabへ移行する目的
今回の移行では、単にコード量を減らすことだけを目的にしていません。
主な目的は、見た目と動作の役割を分けることです。
Scene・Prefab側
・位置
・大きさ
・アンカー
・画像
・文字の見た目
・スクロール範囲
C#側
・表示する数値
・セーブデータ
・ボタンを押したときの処理
・画面の状態
・クエストやキャラクターのデータ
これにより、UIの位置を直したいときはSceneビュー、動作を変えたいときはC#というように、修正する場所を判断しやすくなります。
移行の進め方
既存のUIを一度にすべて削除すると、動いていた機能まで失う危険があります。
そのため、既存処理を残しながら、画面単位で段階的に移行しました。
1. UIの構造をSceneへ配置する
最初にCanvasの下へ、画面全体の親となるオブジェクトを配置します。
ホーム画面であれば、主に次の領域へ分けました。
Menu Canvas
├─ Header
├─ Home Screen
│ ├─ Main Content
│ └─ Buttons
└─ Bottom Navigation
上部ステータス、中央のコンテンツ、下部タブを分けることで、それぞれのアンカーと表示範囲を設定しやすくなります。
2. 再利用する部分をPrefab化する
複数画面で使用する部品は、Prefabとして分けます。
- 上部ステータス
- 下部ナビゲーション
- クエストカード
- キャラクターカード
- 汎用ボタン
- 選択中の枠
同じ部品をPrefabから生成すれば、枠や文字位置を修正したときに複数画面へ反映できます。
一方、画面ごとに構造が大きく異なる部分は、無理に共通化しないようにしました。
3. スクリプトから参照する
SceneやPrefabへ配置したUIを、スクリプトから参照します。
コード側では新しいオブジェクトを毎回作るのではなく、すでに配置されているテキスト、画像、ボタンへ値を設定します。
ランク表示 ← セーブデータのランク
スタミナ表示 ← 現在値と最大値
ゴールド表示 ← 所持数
クエストカード ← クエストデータ
キャラカード ← CharacterData
これにより、表示内容はこれまでどおり動的に更新しながら、位置とサイズはInspectorで調整できます。
Sceneに表示されない問題
移行中、一部の画面はPlayモードでは表示されるものの、停止中のSceneビューには表示されない状態になりました。
考えられる原因を確認すると、実行時に画面を生成する既存処理がまだ残っていました。
Sceneへ保存されているUIではなく、Playモード開始後にコードから別のUIが作られていたため、実行中と停止中で状態が異なっていました。
この状態では、Scene上で編集している画面と、実際にゲームで表示される画面が一致しません。
そのため、どのUIがSceneに保存されたものか、どのUIが実行時に生成されたものかを整理する必要がありました。
自動再生成を止めた
UIのPrefabとSceneを作り直すためのEditorスクリプトには、Unity起動時やコードの再コンパイル時に自動実行される処理がありました。
自動生成は初期構築には便利ですが、手作業で位置を調整したあとにも再生成されると、変更が上書きされる可能性があります。
そこで、自動実行に使っていた処理を外し、必要なときだけ手動で再構築する方針へ変更しました。
具体的には、起動時の自動実行に関係する次の仕組みを使用しないようにしました。
InitializeOnLoad
EditorApplication.delayCall
再構築が必要な場合は、Unity Editorのメニューから明示的に実行します。
FlickBattle > UI > Rebuild Menu UI
普段の細かな調整では再構築せず、SceneとPrefabを直接編集します。
これにより、Unityの起動やスクリプトの再コンパイルによって、意図せずUIが作り直されることを防ぎました。
移行後に調整しやすくなったこと
uGUIとPrefabへ移行したことで、Playモードを開始しなくても、SceneビューでUIの位置関係を確認できるようになりました。
特に、次の調整がしやすくなりました。
- キャラクター名を少し上へ移動する
- レベルと星の位置をそろえる
- カード同士の間隔を変更する
- 文字色や縁取りを確認する
- ボタンの大きさを調整する
- 上部ステータスとスクロール領域の境界を確認する
- 下部タブのアイコンが枠内に収まっているか確認する
コード内の数値を探すよりも、対象のRectTransformを選択して変更できるため、細かな修正は自分で行いやすくなりました。
画面切り替えはどうするか
ホーム、キャラクター、クエスト、編成、設定などのメニュー画面は、同じCanvas内に画面ごとの親オブジェクトを用意する構成にしました。
表示する画面だけを有効にし、それ以外を非表示にします。
Home Screen ON
Character Screen OFF
Quest Screen OFF
Formation Screen OFF
Settings Screen OFF
タブを押したときは、対象画面を表示してほかの画面を閉じます。
Sceneビューで別画面を調整するときも、編集したい親オブジェクトを一時的に有効にすれば確認できます。
ただし、実行時の初期化処理によってホーム画面だけが再び有効になる場合があります。そのため、Scene上の編集状態と、ゲーム開始時の初期表示処理は分けて考える必要があります。
移行してもコードは必要
uGUIとPrefabへの移行は、コードを使わなくする作業ではありません。
見た目をSceneへ移したあとも、次の処理はC#で実装します。
- セーブデータを読み込む
- ランク経験値をゲージへ反映する
- スタミナの回復時間を更新する
- クエストの解放状態を判定する
- クリア済み表示や鍵マークを切り替える
- キャラクターのレベルや属性を表示する
- ボタンから別画面や戦闘Sceneへ遷移する
重要なのは、コードをなくすことではなく、コードが見た目の座標まで管理しない構成にすることです。
今回の移行で学んだこと
自動生成は初期構築に向いている
多数のUIを最初に用意するとき、自動生成は便利です。
しかし、デザインが固まり、数ピクセル単位の調整へ入ったあとも自動生成を続けると、手作業の変更と競合しやすくなります。
初期構築と日常的な調整で、使用する方法を分けた方がよいと感じました。
Prefab化する範囲を決める必要がある
すべてをひとつの巨大なPrefabにすると、画面ごとの修正が難しくなります。
反対に、細かく分けすぎるとPrefabの数が増え、参照関係が複雑になります。
複数箇所で再利用する部品、同じ構造を繰り返すカード、独立して調整したい領域をPrefab化するのが扱いやすいと感じています。
実機確認は引き続き必要
Sceneで見えるようになっても、Android端末での表示が保証されるわけではありません。
Canvas Scaler、Safe Area、画面比率、タッチ操作、スクロール感覚などは、実機で確認する必要があります。
Sceneでの調整がしやすくなったことで、問題を直して実機で再確認するまでの流れを短くできることが、今回の移行の大きな利点です。
現在の進捗と今後
現在は、ホーム画面だけでなく、クエスト画面、キャラクター一覧、キャラクター詳細なども、新しい構成で調整を進めています。
クエスト画面ではエリア一覧からクエスト一覧へ移動し、選択したクエストから戦闘へ遷移する流れを整える予定です。
キャラクター画面では、一覧から詳細、強化へ移動できる構成を作っています。
今後は次の項目を進めます。
- Android実機での再確認
- 異なる画面比率での表示確認
- クエストカードと上部ステータスの重なり修正
- タブアイコンの欠け修正
- スクロール範囲と方向の確認
- 各画面のPrefab構成整理
- 不要になったコード生成処理の段階的な削除
まとめ
コード生成中心のUIは、最初に画面を作る段階では便利でした。しかし、ゲームのデザインを整え、実機に合わせて細かく修正する段階では、Play中にしか確認できないことが大きな負担になりました。
そこで、見た目と配置をuGUIおよびPrefab、データと動作をC#で管理する構成へ移行しました。
移行中には、Sceneに保存されたUIと実行時に生成されたUIが混在する問題や、自動再生成によって調整内容が上書きされる可能性もありました。
自動再生成を止め、必要なときだけ手動で再構築することで、Sceneビューから細かな調整を行いやすくなりました。
今後は、各画面の移行を進めながら、Android実機での表示と操作を確認していきます。