メインコンテンツまでスキップ

UIシステム概要

OpenMonのUIレイヤーは Assets/OpenMon/Core/Runtime/UI/ にあり、UnityのUGUI(Canvas + RectTransform)上に完全に構築されています。すべての画面、メニュー、ダイアログは、ナビゲーション可能なリスト/グリッドのための MenuSelector と、モーダルテキストボックス、選択肢、複雑なポップアップのための DialogManager という2つの基礎的な構成要素を共有しています。

アーキテクチャ概要​

UI/
├── MenuSelector.cs # すべてのナビゲーション可能なメニューの基底クラス
├── ScrollableMenuSelector.cs # MenuSelector + ScrollRectサポート
├── VirtualizedMenuSelector.cs # MenuSelector + リサイクル/プールされたアイテム
├── MenuItem.cs # MenuSelector内の個別ボタン
├── VirtualizedMenuItem.cs # プール内の行を認識するMenuItem
├── UIElementsInstaller.cs # UIファクトリ用のZenjectインストーラー
├── Battle/ # バトルHUD:メインメニュー、技メニュー、ターゲット選択
├── Bags/ # タブ付きインベントリ/バッグ画面
├── Dex/ # タブ付きフル図鑑スタイル画面
├── Dialogs/ # DialogManager + 選択肢メニュー、テキスト入力、ポップアップ
├── GameMenu/ # ゲーム内一時停止メニュー(図鑑、モンスター、バッグ、マップなど)
├── MainMenu/ # タイトル画面:ニューゲーム、続きから、クレジット
├── Monsters/ # モンスターロスター画面、サマリー、ストレージ
├── Options/ # 設定画面(音量、解像度、言語など)
├── Shops/ # 売買ショップインターフェース
├── Quests/ # クエストログ画面
├── Profile/ # プレイヤープロフィール / トレーナーカード
├── Map/ # ワールドマップオーバーレイ
└── ...

2つの柱​

MenuSelector は、ほぼすべてのインタラクティブメニューが継承する基底クラスです。以下を処理します:

  • VerticalまたはHorizontalナビゲーション — Navigation enumによる。
  • セレクター矢印 — MCE 同梱のトゥイーン API でホバーされたアイテムへアニメーション移動。
  • オーディオフィードバック — ナビゲーションと選択時。
  • 入力統合 — IInputReceiver インターフェースと IInputManager を通じて。
  • Wrap-around — 最後のアイテムから先へ進むと最初に戻り、その逆も同様。
  • Hold-to-scroll — CanHoldToScrollFaster が有効な場合、入力を押し続けると設定可能な間隔でナビゲーションを繰り返す。

2つの特殊なバリアントがあります:

クラスユースケース
ScrollableMenuSelector選択アイテムを表示し続けるために自動スクロールする ScrollRect を追加。
VirtualizedMenuSelector<TData, TButton, TFactory>大量データ(例:図鑑、ストレージ)用のオブジェクトプールリスト。プレイヤーのスクロールに合わせてボタンインスタンスをリサイクル。

詳細はメニューページを参照。

DialogManager — モーダルダイアログと複雑なポップアップ​

DialogManager は、ゲーム内のすべてのモーダルUIオーバーレイを所有する Singleton です。以下を管理します:

  • 基本テキストダイアログ — タイプライターアニメーション、話者名パネル、ローカライゼーション付き。
  • 選択肢メニュー — はい/いいえ、最大11の選択肢。
  • フルスクリーン画面 — 静的メソッドでアクセス可能:図鑑、バッグ、ロスター、ショップ、オプション、プロフィール、クエスト、マップ。
  • 特殊ポップアップ — XP獲得パネル、技置き換えダイアログ、技教え、新モンスターポップアップ、テキスト入力ダイアログ。
  • 通知 — 子の NotificationManager を通じて。

DialogManagerはZenjectのファクトリーパターンでインスタンス化されます:

// DialogManagerInstaller.cs
Container.BindFactory<DialogManager, DialogManager.Factory>()
.FromComponentInNewPrefab(Prefab);

詳細はダイアログページを参照。

依存性注入​

すべてのUIファクトリは、2つのZenject ScriptableObjectInstaller を通じて登録されます:

  • DialogManagerInstaller — プレハブから DialogManager.Factory をバインド。
  • UIElementsInstaller — アイテムボタン、モンスターボタン、図鑑ボタン、技ボタン、クエストボタン、セーブデータボタンなどのファクトリをバインド。各バインディングは .WhenInjectedInto<T>() でスコープ設定され、画面ごとに正しいプレハブバリアントが使用される。
// UIElementsInstallerの例
Container.BindFactory<ItemButton, ItemButton.Factory>()
.FromComponentInNewPrefab(BagItemButtonPrefab)
.AsCached()
.WhenInjectedInto<BagTab>()
.Lazy();

専用画面コントローラー​

各主要画面は、MenuSelector(グリッド/リストナビゲーション用)、VirtualizedMenuSelector(大規模プールリスト用)、または HidableUiElement(カスタムレイアウト用)を拡張します。すべて DialogManager を通じて起動されます:

画面コントローラー基底クラス起動方法
ゲームメニューGameMenuScreenMenuSelectorDialogManager.ShowGameMenu(...)
モンスターロスターMonstersMenuScreenHidableUiElementDialogManager.ShowPlayerRosterMenu(...)
バッグ / インベントリBagScreenHidableUiElementDialogManager.ShowBag(...)
図鑑DexScreenVirtualizedMenuSelectorDialogManager.ShowDexScreen(...)
単体モンスター図鑑SingleMonsterDexScreenHidableUiElementDialogManager.ShowSingleMonsterDexScreen(...)
ショップShopDialogHidableUiElementDialogManager.ShowShop(...)
オプションOptionsScreenMenuSelectorDialogManager.ShowOptionsMenu()
プロフィールProfileScreenHidableUiElementDialogManager.ShowProfileScreen(...)
クエストQuestsScreenVirtualizedMenuSelectorDialogManager.ShowQuestsScreen(...)
テキスト入力TextInputDialogHidableUiElementDialogManager.RequestTextInput(...)
技教えMoveTutorDialogHidableUiElementDialogManager.ShowMoveTutorDialog(...)

バトルUI​

バトルHUDには、DialogManagerによって管理されない独自の MenuSelector サブクラスセットがあります:

コントローラー基底クラス目的
MainBattleMenuMenuSelectorたたかう / バッグ / モンスター / にげる の選択
BattleMoveMenuSelectorMenuSelectorバトル中の技選択
TargetMonstersMenuSelectorMenuSelector複数バトルでのターゲット選択
BattleMonstersMenuHidableUiElementバトル中のモンスター交代
BattleInfoPanelHidableUiElement<MoveInfoPanel>詳細バトル状態オーバーレイ
LastBallMenuMenuSelector最後に使ったボールのクイックスロー

入力システム統合​

すべてのメニューは IInputReceiver を実装しており、これはUnityの新しい入力システムのアクションインターフェースを拡張しています:

public interface IInputReceiver : MCEInputActions.IMainActions,
MCEInputActions.IUIActions,
MCEInputActions.ITextInputActions
{
InputType GetInputType();
void OnStateEnter();
void OnStateExit();
string GetDebugName();
}

IInputManager はレシーバーのスタックを維持します。メニューが RequestInput() を呼び出すと、自身をスタックにプッシュしてアクティブなレシーバーになります。ReleaseInput() を呼び出すとポップされます。これによりネストされたメニューが自然に処理されます — ゲームメニューからバッグを開くとバッグの入力レシーバーが上にプッシュされ、閉じるとゲームメニューに入力が戻ります。

カスタムUI画面のベストプラクティス​

  1. MenuSelector を継承する(大規模リストの場合は ScrollableMenuSelector / VirtualizedMenuSelector)。
  2. 各ボタンに MenuItem コンポーネントを追加する。セレクター矢印用に ArrowSelectorPosition トランスフォームを設定する。
  3. 画面がプール/仮想化アイテムを使用する場合は UIElementsInstaller にファクトリを登録する。
  4. 既存のパターンに従い、静的メソッドとシリアル化参照を追加して DialogManager から起動する。
  5. すべてのインスペクター参照に [SerializeField] private を使用する — APIの一部でない限り、フィールドを public として公開しない。
  6. プレイヤーが見るすべてのテキストにローカライゼーションキーを使用する。LocalizedTextMeshPro と LocalizedTypeWriterTMP コンポーネントが自動的に処理する。
  7. 新しいエディターツールにはUI Toolkitを優先するが、既存システムとの一貫性を維持するため、ランタイムゲームUIにはUGUIを引き続き使用する。