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

ダイアログシステム

ダイアログシステムは、シンプルなテキストボックスからバッグ、図鑑、モンスターロスターのような全画面メニューまで、すべてのモーダルUIのためのエンジン中央ハブです。DialogManager シングルトンを中心に構築され、タイプライターアニメーション、ローカライゼーション、分岐選択肢を備えたキュー型アーキテクチャを使用しています。

DialogManager​

場所: Assets/OpenMon/Core/Runtime/UI/Dialogs/DialogManager.cs 名前空間: OpenMon.MCE.UI.Dialogs

DialogManager は Singleton<DialogManager> を拡張し、IInputReceiver を実装します。完全に静的なAPIを提供します — すべてのパブリックメソッドは DialogManager.ShowDialog(...)、DialogManager.ShowChoiceMenu(...) などとして呼び出されます。

Zenjectファクトリによるインスタンス化​

DialogManagerは手動でシーンに配置されません。実行時にZenjectを通じてインスタンス化されます:

// DialogManagerInstaller.cs
[CreateAssetMenu(menuName = "MCE/Dependency Injection/Dialog Manager Installer",
fileName = "DialogManagerInstaller")]
public class DialogManagerInstaller : ScriptableObjectInstaller
{
public DialogManager Prefab;

public override void InstallBindings() =>
Container.BindFactory<DialogManager, DialogManager.Factory>()
.FromComponentInNewPrefab(Prefab);
}

DialogManager.Factory は GameObjectFactory<DialogManager> で、プレハブを作成しZenjectがすべての依存関係を注入できるようにします。

注入される依存関係​

[Inject] private IInputManager inputManager;
[Inject] private ILocalizer localizer;
[Inject] private Roster playerRoster;
[Inject] private EvolutionManager evolutionManager;
[Inject] private MapSceneLauncher mapSceneLauncher;

基本テキストダイアログ​

シンプルなダイアログの表示​

// 発火して忘れる:テキストを表示し、プレイヤーの入力を待つ
DialogManager.ShowDialog("Dialogs/Welcome");

// キャラクター話者付き
DialogManager.ShowDialog("Dialogs/ProfGreeting", character: professorData);

// テキスト修飾子付き(ローカライゼーション経由の文字列補間)
DialogManager.ShowDialog("Dialogs/XPGain/Single",
localizableModifiers: false,
modifiers: new[] { monsterName, "500" });

表示して待機(コルーチン)​

連続したダイアログフローには、コルーチンバリアントを使用します:

yield return DialogManager.ShowDialogAndWait("Dialogs/Moves/Learnt",
localizableModifiers: false,
modifiers: new[] { monsterName, moveName });

これはプレイヤーがダイアログを閉じるまでコルーチンをブロックします。

ShowDialogの完全なシグネチャ​

public static void ShowDialog(
string localizationKey,
CharacterData character = null,
MonsterInstance monster = null,
bool acceptInput = true,
float typewriterSpeed = .01f,
float switchToNextAfterSeconds = -1, // -1 = 入力を待つ
bool localizableModifiers = true,
BasicDialogBackground background = BasicDialogBackground.Normal,
HorizontalAlignmentOptions horizontalAlignment = HorizontalAlignmentOptions.Left,
params string[] modifiers
);

パラメーターの説明​

パラメーター目的
localizationKeyローカライゼーションシステムのキー(例:"Dialogs/Welcome")
character設定すると、話者パネルにキャラクターの名前を表示
monster設定すると、話者パネルにモンスターの名前/ニックネームを表示
acceptInputプレイヤーがダイアログを進める/閉じることができるか
typewriterSpeedタイプライターアニメーションの1文字あたりの秒数
switchToNextAfterSecondsN秒後に自動進行(-1 = 手動)
localizableModifierstrueの場合、修飾子文字列はローカライゼーションキーとして扱われ、falseの場合はリテラルテキストとして使用
backgroundNormal または Sign(異なる視覚的背景)
modifiersローカライズされた文字列の {0}、{1} などに代入される値

DialogText構造体​

各ダイアログは内部的に読み取り専用構造体 DialogText として表現されます:

public readonly struct DialogText
{
public readonly string LocalizationKey;
public readonly string[] Modifiers;
public readonly bool LocalizableModifiers;
public readonly CharacterData Character;
public readonly MonsterInstance Monster;
public readonly float TypewriterSpeed;
public readonly float SwitchToNextAfterSeconds;
public readonly BasicDialogBackground Background;
public readonly HorizontalAlignmentOptions HorizontalAlignment;
}

ToString(ILocalizer) メソッドはローカライゼーションキーを解決し、修飾子を代入します:

public string ToString(ILocalizer localizer)
{
string text = localizer[LocalizationKey];
for (int i = 0; i < Modifiers.Length; i++)
{
string modifier = Modifiers[i];
text = text.Replace("{" + i + "}", LocalizableModifiers ? localizer[modifier] : modifier);
}
return text;
}

ダイアログキューとフロー​

DialogManagerは内部キューを使用して複数の連続ダイアログを処理します:

ShowDialog("key1") ──► DialogTextをキューに追加
ShowDialog("key2") ──► DialogTextをキューに追加
ShowDialog("key3") ──► DialogTextをキューに追加

プレイヤーが選択ボタンを押す:
├─ タイプライターがまだアニメーション中 → SkipTypewriter()
└─ テキストが完全に表示された → NextDialogInternal()
├─ 現在のテキストにさらにページがある → ページを進める
├─ キューにさらにダイアログがある → デキューして次を表示
└─ キューが空 → 入力を解放、ダイアログを非表示、active = false

ダイアログの待機​

// ダイアログキューが空になるまで待機
yield return DialogManager.WaitForDialog;

// タイプライターがまだアニメーション中である間待機
yield return DialogManager.WaitForTypewriter;

自動進行​

switchToNextAfterSeconds > 0 の場合、タイプライターが終了し指定された遅延が経過した後、ダイアログは自動的に進行します:

private IEnumerator NextDialogAfterSeconds(float seconds)
{
yield return new WaitWhile(() => Text.IsTypewriting);
yield return new WaitForSeconds(seconds);
NextDialog();
}

タイプライターアニメーション​

テキストは LocalizedTypeWriterTMP を使用して表示されます。これは MCETextAnimator をラップしています — トゥイーンベースのタイプライターです。 以下の DOTween 型は MCE 自身のファサード OpenMon.Foundation.Tweening.DOTween(エンジンに同梱)であり、 Demigiant のアセットではありません:

// MCETextAnimator.ShowText()
textComponent.maxVisibleCharacters = 0;
typewriterTween = DOTween.To(
() => textComponent.maxVisibleCharacters,
x => textComponent.maxVisibleCharacters = x,
totalCharacters,
totalCharacters * waitForNormalChars
).SetEase(Ease.Linear)
.OnComplete(() => onTextShowed.Invoke());

速度制御​

LocalizedTypeWriterTMP.SetTypewriterSpeed(float) は3つのタイミング階層を設定します:

階層変数目的
通常waitForNormalChars1文字あたりの基本遅延
中間waitMiddleカンマでの遅延(デフォルトで通常の5倍)
長waitLongピリオドでの遅延(デフォルトで通常の20倍)

テキストエフェクト​

MCETextAnimator はオプションの頂点エフェクトをサポートしています(デフォルトでは無効):

  • <wave> — 文字ごとの正弦波垂直振動。
  • <shake> — フレームごとの文字ごとのランダムオフセット。

コンポーネントで enableVertexEffects = true を設定して有効にします。

スキップ​

タイプライターがアニメーション中に選択ボタンを押すと SkipTypewriter() が呼び出され、すべての文字が即座に表示されます。

話者パネル​

CharacterData または MonsterInstance が渡されると、ダイアログは話者名パネルを表示します:

if (nextText.Character != null)
{
CharacterName.SetValue(nextText.Character.LocalizableName);
CharacterPanel.Show();
}
else if (nextText.Monster != null)
{
CharacterName.Text.SetText(nextText.Monster.GetNameOrNickName(localizer));
CharacterPanel.Show();
}
else
CharacterPanel.Show(false);

選択肢メニュー​

選択肢ダイアログは ChoiceMenuController を使用します — 1〜11のオプションを自動サイズ調整でサポートする MenuSelector のサブクラス:

DialogManager.ShowChoiceMenu(
options: new List<string> { "Common/True", "Common/False" },
callback: choice => { /* 0 = はい, 1 = いいえ */ },
onBackCallback: () => { /* キャンセルとして扱う */ },
showDialog: true,
localizationKey: "Menu/Save/Confirmation"
);

ShowChoiceMenuの完全なシグネチャ​

public static void ShowChoiceMenu(
List<string> options, // 各オプションのローカライゼーションキー
Action<int> callback, // 選択されたインデックスで呼び出される
Transform position = null, // カスタム位置(null = デフォルト)
Action onBackCallback = null, // 設定すると、戻るボタンで閉じてこれを呼び出す
CharacterData character = null, // 話者
MonsterInstance monster = null, // 話者
bool showDialog = false, // 選択肢と一緒にテキストダイアログを表示
string localizationKey = "", // ダイアログテキストのローカライゼーションキー
bool localizableModifiers = true,
params string[] modifiers
);

内部の動作​

  1. ChoiceMenuController.SetNumberOfOptions(n) は最初のN個の ChoiceOption アイテムを有効にし、パネルをリサイズします。
  2. 各オプションの LocalizedTextMeshPro が提供されたローカライゼーションキーに設定されます。
  3. 選択肢メニューはタイプライターが終了した後に表示されます(showDialog がtrueの場合)。
  4. 選択時、コールバックが発火し、選択肢メニューは自動的に非表示になります。
  5. 戻る場合(許可されていれば)、onBackCallback が発火します。

一般的なパターン:コルーチンを使ったはい/いいえ​

int choice = -1;

DialogManager.ShowChoiceMenu(
new List<string> { "Common/True", "Common/False" },
playerChoice => choice = playerChoice,
onBackCallback: () => choice = 1,
showDialog: true,
localizationKey: "Menu/Save/Confirmation"
);

yield return new WaitUntil(() => choice != -1);

if (choice == 0)
{
// プレイヤーは「はい」を選んだ
}

ローカライゼーション統合​

すべてのダイアログテキストは ILocalizer システムを通過します:

  • LocalizedTextMeshPro.SetValue(key, localizableModifiers, modifiers) はキーを解決し、{0}、{1} などを代入します。
  • localizableModifiers がtrueの場合、修飾子文字列自体がローカライゼーションキーとして解決されます。
  • falseの場合、修飾子はリテラル文字列として挿入されます(プレイヤー名、番号などに便利)。
// ローカライズ可能な修飾子:「Dialogs/Caught」と「Monsters/Pikachu」の両方が解決される
DialogManager.ShowDialog("Dialogs/Caught", modifiers: "Monsters/Pikachu");

// リテラル修飾子:「500」がそのまま挿入される
DialogManager.ShowDialog("Dialogs/XPGain/Single",
localizableModifiers: false,
modifiers: new[] { monsterName, "500" });

複雑なダイアログ(管理画面)​

基本テキスト以外にも、DialogManager はすべての主要画面への参照を保持し、静的な起動メソッドを提供します:

メソッド開くもの
ShowGameMenu(...)ゲーム内一時停止メニュー
ShowPlayerRosterMenu(...)モンスターパーティ画面(選択/交換モード付き)
ShowBag(...)タブ付きインベントリ(バトルモード、販売モード、選択モード)
ShowDexScreen(...)完全な図鑑ブラウザ
ShowSingleMonsterDexScreen(...)単一モンスター図鑑エントリ
ShowShop(...)売買ショップ
ShowOptionsMenu()設定画面
ShowProfileScreen(...)トレーナーカード
ShowQuestsScreen(...)クエストログ
RequestTextInput(...)キーボード入力ダイアログ(命名など)
ShowMoveTutorDialog(...)技教え選択
ShowMoveLearnPanel(...)技習得/置き換えフロー
ShowNewMonsterDialog(...)新モンスターのニックネーム + ストレージフロー
ShowXPGainDialogLearnMoveAndEvolveForSingleMonsterInPlayerRoster(...)XP獲得 → レベルアップ → 技習得 → 進化の完全パイプライン
CloseMenus()開いているすべての画面を順に閉じる

通知​

DialogManager.Notifications は子の NotificationManager を公開し、トースト形式の通知を提供します:

DialogManager.Notifications.StopAllNotifications();

ローディングインジケーター​

DialogManager.ShowLoadingIcon(true);
DialogManager.ShowLoadingText("Loading/MapData");
// ... 非同期処理 ...
DialogManager.ClearLoadingText();
DialogManager.ShowLoadingIcon(false);

CommandGraphからのダイアログ使用​

NPCの動作は CommandGraph(ノードベースのビジュアルスクリプティングシステム)で作成されます。ダイアログノードは内部的に同じ DialogManager.ShowDialog(...) および DialogManager.ShowChoiceMenu(...) 静的APIを呼び出します。CommandGraphノードは以下を処理します:

  • 複数のダイアログテキストを連続して連結
  • 選択結果に基づく分岐
  • ノードごとの話者キャラクター設定
  • グラフを進める前にダイアログ完了を待機

コードからは同じ静的メソッドとやり取りします — 基盤となるAPIに違いはありません。

背景のバリアント​

BasicDialogBackground は DialogManager 内にネストされた列挙型です(つまり DialogManager.BasicDialogBackground):

// DialogManager内で定義
public enum BasicDialogBackground
{
Normal, // 標準ダイアログボックス
Sign // 看板 / 掲示板スタイル
}

background: DialogManager.BasicDialogBackground.Sign を ShowDialog() に渡して看板バリアントを使用します。DialogManagerは、SerializableDictionary<BasicDialogBackground, HidableUiElement> に保存されたシリアル化された背景 HidableUiElement 参照を切り替えます。