各UI画面へのアクセスとしての画面作りをしていきます。
ボタンはメイン画面に直置きも良いですが、汎用的な「メニュー画面」を実装していきます。
メイン画面に置くボタンは「メニュー」「スキップ」「オート」あたりになると思います。
メニュー画面の実装
Panel方式
今回はとくに機能的追加はないので、いままのでUI画面と同じ挙動の空画面を作るようなイメージです。
しかし、
「そのまま各ボタンの配置(ボタンのほうに開く機能)」にするか「画面自体にボタン機能をつける」かで迷いました。
このあたりが若干、他のエンジンとの差を感じました。
空画面としての役割ならば、そのままボタン配置で良く、カスタム性もあります。
画面自体に機能を付けてボタンをアサインする方法でも、やってることは変わらないですが、
「メニュー画面」の機能とすることで「メニュー画面」という位置付けにすることができそうです。
実際、将来は違う形になっているかもしれませんが、とりあえずこの形で実装してみることにしました。

いままで仮Canvasに置いてあったボタンたちをアサインして画面を作っていきます。
他のUI画面と同じPanel方式にもなったので、良かったのではないかと思います。
プロジェクトまとめ
■ 目的
メイン画面から呼び出す「UIメニュー画面」の実装:各設定画面へのハブとして機能させる。
■ 構成
UI_MenuPanel(UI_PanelBase継承)
├ Closeボタン
├ Saveボタン
├ Loadボタン
├ System設定ボタン
├ Audio設定ボタン
├ Text設定ボタン
└ Title戻るボタン
■ スクリプト構造:基本構造(他UIと統一)
- UI_PanelBase 継承
- Instance シングルトン
- Awake() で初期化
- Start() でイベント登録
- Update() で右クリック閉じる
■ 現在の仕様
- UIは重ねて表示される
- メニューの上に各設定画面が出る
- 各UIは独立した「UI_PanelBase」管理
UIスタック管理システム(入力専用)
現状、メニュー画面と他UI画面が連動しているので、閉じる挙動ですべてが閉じる形になっています。
なので、画面を別々に制御するために「UI_Manager」を作って管理させます。
■ 全体構成
UI_Manager(新規)
├ Stack
├ 入力処理(右クリック)
└ CloseTop()
UI_PanelBase(修正)
├ Open → Register
└ Close → Unregister
各UI
└ Update削除(←重要)
■ 将来の分離
- UI_Manager → UI制御
- Sys_InputManager → ゲーム入力制御

■ 配置ルール
- UI_Manager → UI_Root外(管理系)
- UI → UI_Root内(表示系)
UIの開き方を2パターンから選べるようにする
メニュー画面の将来性を考えてみると、
- フル画面のメニュー画面が開かれる → 他UI画面が重なっていく
透明度にもよるが、メニュー画面自体は表示されたままでも良い
- フル画面ではなく、上下左右からボタン尺の飛び出すメニューを作る場合、
他UI画面を表示する際にその表示されたメニューは閉じてほしい
という挙動を想定できます。
もしくは、UI画面がさらに重なった場合、下のUI画面はそのままでいい場合と閉じたい場合。
この2つの挙動を選択設定できるように機能を追加します。

各UI画面(Canvas)毎に設定が選べるようになったので、臨機応変に挙動を変えられます。
今回のメニュー画面はボタン配置だけだったので、すんなり実装と想定していたのですが、
他UI画面と同じ挙動(開く閉じる)に統一するのにちょっと手間取りました。
いままでスクリプトを作り上げてきたのは自分ではないので、スクリプトの構成を理解できていないのが大きな要因です。
あとはChatGPTの途中提案に「モーダル制御」(画面操作の誤作動をより制御するシステム)というものがあり、
どうせならばと試みたのですが、どうにもごちゃごちゃしてきてしまい、
元に戻す工程でUnityプロジェクトにエラー頻発で結構焦りました…
そして、
とりあえず当初の目標であるUI画面がすべてそろったので、
保留だった自動でソート(画面の重なり具合)を決めてもらう「UIソートシステム」も実装しておきました。
内部で何が起こってるのかよく分かっていませんが、きっとうまく動いてるはずです…
UI自動ソートシステム
目的
- UI画面の表示順序を自動で管理し、手動での SortOrder 管理を不要にする
- Stack 管理により、Additive / Replace モードに対応
- 右クリックでトップUIを閉じる挙動を統一
- UI_Root 配下のCanvasのみ自動ソート対象とすることで、暗幕や外部Canvasの影響を排除
構成
■ UI_PanelBase.cs(全UI共通基底)
- OpenMode 列挙型
- Additive:重ねて表示
- Replace:開くとき全UIを閉じる
- Open()
- Replace の場合は UI_Manager の CloseAll() 呼び出し
- 入力ブロック(Sys_InputManager)
- PanelObject のアクティブ化
- Canvas の SortOrder 自動設定(UI_Root 配下のみ、Black_Canvas は固定999)
- UI_Manager へ登録
- Close()
- 入力ブロック解除
- PanelObject 非アクティブ化
- UI_Manager から登録解除
■ UI_Manager.cs(UI全体管理)
- Stack による UI 登録・削除:Register()/Unregister() で Stack 管理
- GetNextSortOrder() で次のSortOrderを取得
- CloseTop() で Stack の最上位 UI を閉じる(右クリック用)
- CloseAll() で全UIを閉じる(Replace モード用)
- Update 内で右クリック監視 → CloseTop() 呼び出し
自動SortOrderのルール
| 対象 | 挙動 |
|---|---|
| UI_Root 配下の Canvas | Open 時に Stack 順で 1,2,3… と自動設定 |
| Black_Canvas(ロード時の暗幕) | 固定 999(最前面) |
| UI_Root 外 Canvas | 自動設定なし、必要に応じ手動 |
※ 初期値はすべて 0 に揃えると安全:さらに安全策として以下の設定を行い現状をキープ
ダイアログ:200
UI_Root 配下の Canvas:100
UI_Root 外 Canvas:0
利用ルール
- UI_Root 配下に Canvas を作成
- UI_PanelBase を継承
- PanelObject をアサイン
- base.Open()/base.Close() を呼ぶ
- SortOrder 初期値は 0 で OK
- Replace モードを使う場合は openMode
=OpenMode.Replace を設定
効果
- UI表示順序を自動管理 → 手動での SortOrder 設定不要
- Stack 管理により右クリック閉じや Replace での挙動が安定
- UI_Root 配下の Canvas は常に表示順が保証される
- 外部Canvasや暗幕は影響を受けない
・将来的に新しい UI を追加するときも、この基盤を使うだけで自動で最前面に表示される
・Replace / Additive の挙動をインスペクターで選択可能
追加修正
- UIをすべて閉じたあとに SortOrder が増え続ける問題
- 次回オープン時に 1,2,3 に戻らない問題
■ 修正方針:スタックが空になった瞬間にリセット
■ 修正箇所①(最重要):Unregister に追加
if (stack.Count == 0)
{
nextSortOrder = 0;
}
UIが閉じられる経路は複数ある:唯一共通するのが Unregister
- CloseTop
- 個別Close
- Replace(CloseAll経由)
- 手動Close
■ 修正箇所②(保険):CloseAll の最後
nextSortOrder = 0;
- 念のための二重保険
- 将来仕様変更しても壊れにくい
■ CloseAllの注意点(ついでに修正済み)
while (stack.Count > 0)
{
var top = stack.Peek();
top.Close();
}
- Close() → Unregister() が内部でPopするため
- 二重Pop防止
■ 最終挙動
- 1 → 2 → 3 → 全閉じ → リセット → 1 → 2 → 3
- 常にクリーンな状態から再スタート

コメント