dialogue-manager について
Dialogue Managerは、読みやすい`.dialogue`ファイルで分岐会話を作成するGodot向けアドオンです。条件判定や状態変更、CSV・PO翻訳フロー、エディタータブ、C#対応を備えています。
主な機能
- 01スクリプト風の`.dialogue`形式
- 02分岐応答と条件判定
- 03状態変更とランダム台詞
- 04CSV・PO翻訳フロー
- 05対話エディタータブ
- 06公式C#対応
活用シーン
- 01テキストファイルでキャラクターの会話を作成
- 02応答選択肢に条件分岐を設定
- 03会話中にゲーム状態を更新
- 04翻訳用に会話テキストをエクスポート
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jame581/ godotprompter --skill dialogue-managerインストール後、Claude Code で/dialogue-managerを入力して読み込まれたか確認します。
詳細
Dialogue Manager
関連スキル: 手作りの対話データ構造には dialogue-system、セリフの翻訳には localization、アドベンチャーゲーム全体のワークフローには popochiu を使用してください。
アドオン: Dialogue Manager · version
v3.10.4· Godot 4.6 · MIT · source: https://github.com/nathanhoad/godot_dialogue_manager · 公式 C# サポート付きの GDScript。
1. Dialogue Manager を使用する場面
| アプローチ | 最適な用途 |
|---|---|
dialogue-system スキル(手作りの Resource データ) | データ構造を完全に制御したい場合、アドオンへの依存を避けたい場合、小規模な対話ツリー |
| Dialogue Manager | スクリプトのような .dialogue テキスト形式、分岐する応答、条件/変更、翻訳パイプライン、ビジュアルエディタータブ、公式 C# ラッパー |
| アドベンチャーゲーム用のフルフレームワーク | 部屋/インベントリ/キャラクターを対話機能とまとめて備える必要があるポイント&クリックゲーム — Dialogue Manager が担うのは対話レイヤーのみ |
ライターが(インスペクターで編集する Resources ではなく)読みやすいスクリプトテキストで分岐する対話を作成したい場合や、組み込みの条件、変更、ランダムなセリフ、翻訳ワークフロー(CSV または PO)をすぐに利用したい場合は、Dialogue Manager を選んでください。完全に自分で管理する、型付けの強い Resources として対話を扱いたい場合は、代わりに dialogue-system を使用してください。Dialogue Manager が扱うのは対話のみで、アドベンチャー/クエスト用のフルフレームワークではありません。そのため、より大規模なポイント&クリック用フレームワークが、部屋、インベントリ、キャラクターを引き続き管理することになります。
2. インストールとセットアップ
- Godot AssetLib → 「Dialogue Manager」を検索 → ダウンロードします。または、GitHub リポジトリ から
addons/dialogue_manager/をres://addons/dialogue_manager/にコピーします。 - Project → Project Settings → Plugins → 「Dialogue Manager」を有効にします。これにより、Dialogue メイン画面タブ(2D/3D/Script の隣)が追加され、
DialogueManagerオートロードも自動的に登録されます。オートロードを手動で設定する必要はありません。 addons/dialogue_manager/plugin.cfg:
[plugin]
name="Dialogue Manager"
description="A powerful nonlinear dialogue system"
author="Nathan Hoad"
version="3.10.4"
script="plugin.gd"
- C# プロジェクトでは NuGet パッケージを追加する必要はありません。
using DialogueManagerRuntime;だけで使用できます(§4)。 - 設定は Project Settings → General → Dialogue Manager にあります。特に、State Autoload Shortcuts(プレフィックスなしで対話内から使用できるオートロード名)と Balloon Path(
show_dialogue_balloon()が開くシーン。空欄の場合は組み込みのサンプル吹き出しを使用)を確認してください。
3. .dialogue 構文
Dialogue エディタータブから .dialogue ファイルを開くか、新規作成します。行は Character: text または text のみ(ナレーター)です。Godot の RichTextLabel BBCode に加えて、拡張構文にも対応しています:[[A|B|C]](インラインの候補からランダムに選択)、[wait=N] / [wait="ui_accept"](入力待ちでタイプ表示を一時停止)、[speed=N]、[next=auto](自動で次へ進む)。
タイトルとジャンプ — ~ name でタイトルを定義し、=> name でジャンプします。=> END でフローを終了し、=> END! で保留中のジャンプとリターンを無視して強制終了します。=>< name でジャンプし、分岐が END に到達するとここに一度戻ります:
~ start
Nathan: Well?
- First one
- Another one => another_title
- Start again => start
=> END
~ another_title
Nathan: Another one?
=> END
選択肢(- )はインデントでネストし、[...] に条件を指定できます — ジャンプは必ず最後に記述します:
Nathan: How many projects have you started and not finished?
- Just a couple
Nathan: That's not so bad.
- A lot [if SomeGlobal.some_property == true]
Nathan: Maybe you should finish one before another.
- Another one [if SomeGlobal.some_method()] => another_title
条件 — if / elif / else、ブール演算子 and/or/(), および match/while ブロック:
if SomeGlobal.some_property >= 10
Nathan: That property is >= 10.
elif SomeGlobal.some_other_property == "some value"
Nathan: Or we might be in here.
else
Nathan: If neither are true, I'll say this.
インライン条件:Nathan: I have done this [if already_done]once again[/if]。[else] も任意で指定できます。Null セーフなメンバーアクセスには ?. を使います:if some_node_reference?.name == "SomeNode"。
状態の変更 — set は状態を割り当て、do はメソッドを呼び出すかシグナルを送出します。どちらもインラインで実行できます([do wave()]。暗黙の await を抑止するには [do! wave()] を使います):
if SomeGlobal.has_met_nathan == false
do SomeGlobal.animate("Nathan", "Wave")
Nathan: Hi, I'm Nathan.
set SomeGlobal.has_met_nathan = true
組み込みの状態変更:do wait(float)、do debug(...)。会話からシグナルを送出するには、do SomeGlobal.some_signal.emit("arg") を使います。
ローカル変数と追加のゲーム状態 — set locals.asked = true は会話ごとの一時変数を作成します(これは example balloon が実装する慣例であり、Dialogue Manager のコア機能ではありません)。extra_game_states 配列で渡されたオブジェクトは名前で直接参照でき、その状態変更は会話の終了後も保持されます — クラスではなくインスタンスを渡してください(GameStateClass.new() を使い、クラスそのものは渡さないでください)。
ランダムな行 — %(等しい重み)または %N(相対的な重み)を先頭に付けます。空行でランダムなグループを区切ります:
Nathan: I will say this.
%3 Nathan: This line has a 60% chance of being picked
%2 Nathan: This line has a 40% chance of being picked
変数とタグ — {{SomeGlobal.some_property}} で状態をテキストに埋め込みます(キャラクター名にも使用できます)。[#happy, #mood=calm] でタグを付与し、line.get_tag_value("mood") で取得できます。
4. 実行時 API と example balloon
DialogueResource(.dialogue ファイル)を読み込み、DialogueManager にバルーンを開かせるか、await DialogueManager.get_next_dialogue_line(resource, title) で行を手動で取得します。次の行がない場合は null が返ります — GDScript では falsy を確認し(if not line: / while line:)、C# では line != null を確認してください。(タグの API.md の説明には「空の辞書 {}」とありますが、v3.10.4 のソースは会話のすべての終了経路で null を返します — line == {} の確認は実行されません。)
GDScript
# npc.gd
extends Node2D
@export var dialogue_resource: DialogueResource
func _on_interact() -> void:
# Opens the configured balloon (Settings → Balloon Path), or the built-in example balloon.
DialogueManager.show_dialogue_balloon(dialogue_resource, "start")
func _manual_walk() -> void:
# Manual traversal — build a totally custom balloon around this loop.
var line: DialogueLine = await DialogueManager.get_next_dialogue_line(dialogue_resource, "start")
while line:
print("%s: %s" % [line.character, line.text])
if line.responses.is_empty():
line = await DialogueManager.get_next_dialogue_line(dialogue_resource, line.next_id)
else:
var chosen: DialogueResponse = line.responses[0] # replace with real UI selection
line = await DialogueManager.get_next_dialogue_line(dialogue_resource, chosen.next_id)
C#
// Npc.cs
using Godot;
using DialogueManagerRuntime;
public partial class Npc : Node2D
{
[Export] public Resource DialogueResource;
private void OnInteract()
{
DialogueManager.ShowDialogueBalloon(DialogueResource, "start");
}
private async void ManualWalk()
{
var line = await DialogueManager.GetNextDialogueLine(DialogueResource, "start");
while (line != null)
{
GD.Print($"{line.Character}: {line.Text}");
if (line.Responses.Count == 0)
{
line = await DialogueManager.GetNextDialogueLine(DialogueResource, line.NextId);
}
else
{
var chosen = line.Responses[0]; // replace with real UI selection
line = await DialogueManager.GetNextDialogueLine(DialogueResource, chosen.NextId);
}
}
}
}
その他の DialogueManager メソッド:show_dialogue_balloon_scene(balloon_scene, resource, title)(指定したバルーンシーンを開く)、show_example_dialogue_balloon(resource, title)(組み込みのバルーンを強制的に使用する)、create_resource_from_text(text)(実行時に .dialogue 文字列をコンパイルする — 構文エラーがあると失敗します)。C# での名前は同じ PascalCase です:ShowDialogueBalloonScene、ShowExampleDialogueBalloon、CreateResourceFromText。
get_next_dialogue_line には mutation_behaviour パラメーターがあります — GDScript では DMConstants.MutationBehaviour、C# では MutationBehaviour です(どちらもデフォルトは Wait、ほかに DoNotWait、Skip があります)。列挙型は DialogueManager オートロードではなく DMConstants にあります。特別な理由がない限り Wait のままにしてください。example balloon がサポートするのは Wait のみです。
5. シグナルと型付きアクセス
DialogueLine のフィールド:id、next_id、character、text、tags(PackedStringArray)、translation_key、responses(型指定のない DialogueResponse の Array)、concurrent_lines。DialogueResponse には、同じ id/next_id/character/text/tags/translation_key フィールドに加えて、is_allowed: bool と condition_as_text: String があります。
GDScript
func _ready() -> void:
DialogueManager.dialogue_started.connect(_on_dialogue_started)
DialogueManager.dialogue_ended.connect(_on_dialogue_ended)
DialogueManager.got_dialogue.connect(_on_got_dialogue)
DialogueManager.mutated.connect(_on_mutated)
func _on_dialogue_started(resource: DialogueResource) -> void:
pass
func _on_dialogue_ended(resource: DialogueResource) -> void:
pass
func _on_got_dialogue(line: DialogueLine) -> void:
print(line.character, ": ", line.text, " tags=", line.tags)
func _on_mutated(mutation: Dictionary) -> void:
pass # fires before a `do`/inline mutation runs (not `set` lines)
C#
using DialogueManagerRuntime;
public override void _Ready()
{
DialogueManager.DialogueStarted += (Resource resource) => { };
DialogueManager.DialogueEnded += (Resource resource) => { };
DialogueManager.GotDialogue += (DialogueLine line) =>
{
GD.Print($"{line.Character}: {line.Text} tags={line.Tags}");
};
DialogueManager.Mutated += (Godot.Collections.Dictionary mutation) => { };
}
⚠️ これらの C# イベントは、
DialogueManager.Instanceに初めてアクセスしたときに、基盤となる Godot シグナルへ遅延して接続されます。ここで購読するだけで、その後 GDScript から会話を進行するプロジェクトでは、Instanceにアクセスしないため、ハンドラーは実行されません。接続するには、C# から API に少なくとも一度アクセスしてください(例:_ = DialogueManager.Instance;、または C# からGetNextDialogueLine/ShowDialogueBalloonを使って会話を実行します)。
組み込みの応答メニューノードは、Godot シグナルとして response_selected のみを公開します。そのため、C# イベントハンドラーではなく、Connect と Callable を使って接続してください。
responsesMenu.Connect("response_selected", Callable.From((DialogueResponse response) =>
{
// advance using response.NextId
}));
passed_title(title)(GDScript)/DialogueManager.PassedTitle += (string title) => { }(C#)は、~ title マーカーを通過するたびに実行されます。分析やセーブポイントのブックマークに便利です。
6. 翻訳
デフォルトでは、すべての会話/応答テキストに Godot の tr() が適用されます。DialogueManager.translation_source プロパティでバックエンドを選択します。列挙型は GDScript の DMConstants.TranslationSource/C# の TranslationSource(None、CSV、PO、デフォルトは Guess)であり、DialogueManager.TranslationSource ではありません。
Guess はロケールのプロジェクト設定を調べて PO ファイルを探し、見つからない場合は CSV にフォールバックします。
行ごとに静的 ID(Nathan: Hi! I'm Nathan. [ID:HI_IM_NATHAN])を指定すると、translation_key が安定して付与されます。これにより、実際のテキストをキーにする代わりに、音声付きの行との照合や CSV/PO の往復変換が可能になります。.dialogue ファイルは POT 生成リストに自動登録されます。会話行の前にある ## コメント行は、エクスポートされた PO/POT 内で #. TRANSLATORS: の注記になります。エディターの Translations メニュー(Dialogue タブ)から CSV をエクスポート/インポートできます。再インポート時に更新されるのは、静的 ID が設定された行のみです。
TranslationServer、ロケールの切り替え、RTL については、localization スキルを参照してください。Dialogue Manager が生成するのは翻訳キーと CSV/PO のエクスポートのみです。実行中のゲームへのロケール変更の組み込みは、localization の役割です。
実装チェックリスト
- Project Settings → Plugins で Dialogue Manager プラグインを有効にする(
DialogueManagerオートロードが自動登録されます) -
.dialogueリソースは手動で解析せず、load()/preload()で読み込む - すべての
get_next_dialogue_line/GetNextDialogueLine呼び出しをawaitする - 手動のトラバーサルループでは、
nullの戻り値で会話の終了を検出する(GDScript ではif not line:、C# ではline != null)。{}との比較は絶対に行わない - 応答行では、
=> targetジャンプの前に[if condition]を置き、後には置かない -
extra_game_statesの項目には、クラスそのものではなくインスタンス(GameStateClass.new())を指定する - 会話から読み書きする C# の状態プロパティには
[Export]を付ける - C# コードでは
using DialogueManagerRuntime;と PascalCase のメンバー(ShowDialogueBalloon、GetNextDialogueLine、DialogueStarted、GotDialogue)を使用する - カスタムの吹き出しは、
show_dialogue_balloonの呼び出し箇所をフォークするのではなく、Settings の Balloon Path を上書きする - 音声や安定した CSV/PO キーが必要な行には、静的翻訳 ID(
[ID:KEY])を追加する - 呼び出し元をブロックすべきでないインラインの
do/awaitによる変更には、do!を使う