dialogue-system について
Godot 4.3+向けの会話システム実装ガイドです。GDScriptとC#の例で、会話データ、分岐ロジック、UI表示を扱います。
主な機能
- 01DialogueLineとDialogueDataのリソース
- 02会話シグナルを持つシングルトン管理
- 03条件付き選択肢と分岐
- 04会話UIとタイプライター効果
- 05JSON読み込みと変数補間
活用シーン
- 01NPCの分岐会話の作成
- 02ゲームUIで台詞と選択肢を表示
- 03JSONから会話テキストを読み込み
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jame581/ godotprompter --skill dialogue-systemインストール後、Claude Code で/dialogue-systemを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/branching-and-conditions.mddialogue-manager.mdexternal-formats.mdui-presentation.mdvariable-interpolation.md詳細
Godot 4.3+ の会話システム
すべての例は、非推奨 API を使わずに Godot 4.3+ を対象としています。まず GDScript を示し、次に C# を示します。
関連スキル: 会話データを Resource として扱う resource-pattern、Control ノードのレイアウトに関する godot-ui、会話のフロー管理に関する state-machine、会話状態の永続化に関する save-load、高機能な会話アドオンに関する dialogue-manager、アドベンチャーゲーム向けの popochiu。
1. アーキテクチャの概要
┌─────────────────────────────────────────────────────────┐
│ UI Layer │
│ DialogueUI (Control) │
│ ├─ Label (speaker_name) │
│ ├─ TextureRect (portrait) │
│ ├─ RichTextLabel (dialogue_text, typewriter effect) │
│ └─ VBoxContainer (choice_container) │
│ └─ Button × N (choice buttons) │
│ │
│ Connects to: line_displayed, choice_presented signals │
└───────────────────────┬─────────────────────────────────┘
│ drives UI via signals
┌───────────────────────▼─────────────────────────────────┐
│ DialogueManager (Autoload / Node) │
│ start_dialogue(dialogue_data) │
│ advance() → next line or end │
│ choose(choice_index) │
│ current_line: DialogueLine (read-only) │
│ │
│ signals: dialogue_started │
│ line_displayed(line) │
│ choice_presented(choices) │
│ dialogue_ended │
└───────────────────────┬─────────────────────────────────┘
│ reads
┌───────────────────────▼─────────────────────────────────┐
│ Data Layer (Resources) │
│ DialogueData (Resource) │
│ lines: Dictionary ← id → DialogueLine │
│ start_line_id: String │
│ │
│ DialogueLine (Resource) │
│ speaker, text, choices, next_line_id, condition │
└─────────────────────────────────────────────────────────┘
2. DialogueLine Resource
DialogueLine は、会話の1つの区切りに関するすべてのデータを保持します。Choices は型指定のない Dictionary の Array なので、別のクラスを用意しなくても、各エントリーに text、next_line_id、省略可能な condition を含められます。
GDScript
# dialogue_line.gd
class_name DialogueLine
extends Resource
## Display name shown in the UI speaker box.
@export var speaker: String = ""
## The body text. Supports BBCode and variable placeholders: {player_name}.
@export_multiline var text: String = ""
## When non-empty, overrides next_line_id. Each Dictionary must have:
## "text" : String — label on the choice button
## "next_line_id": String — line to jump to when chosen
## "condition" : String — (optional) expression; omit or "" to always show
@export var choices: Array = []
## ID of the next DialogueLine. Ignored when choices is non-empty.
@export var next_line_id: String = ""
## Optional condition expression evaluated before displaying this line.
## If the expression returns false the manager skips to next_line_id.
## Example: "GameState.has_item('key')"
@export var condition: String = ""
C#
// DialogueLine.cs
using Godot;
using Godot.Collections;
[GlobalClass]
public partial class DialogueLine : Resource
{
/// <summary>Display name shown in the speaker box.</summary>
[Export] public string Speaker { get; set; } = "";
/// <summary>Body text. Supports BBCode and {variable} placeholders.</summary>
[Export(PropertyHint.MultilineText)]
public string Text { get; set; } = "";
/// <summary>
/// When non-empty, overrides NextLineId. Each Dictionary entry must contain:
/// "text" : string — choice button label
/// "next_line_id" : string — line to jump to
/// "condition" : string — (optional) expression; omit or "" to always show
/// </summary>
[Export] public Array Choices { get; set; } = new();
/// <summary>ID of the next DialogueLine. Ignored when Choices is non-empty.</summary>
[Export] public string NextLineId { get; set; } = "";
/// <summary>
/// Optional condition expression. Evaluated before displaying this line.
/// Example: "GameState.HasItem(\"key\")"
/// </summary>
[Export] public string Condition { get; set; } = "";
}
3. DialogueData Resource
DialogueData は、文字列 ID をキーとするすべての行の Dictionary を保持するコンテナー Resource です。.tres ファイルとして作成すると、インスペクターで NPC に割り当てられます。
GDScript
# dialogue_data.gd
class_name DialogueData
extends Resource
## Dictionary mapping line ID strings to DialogueLine resources.
## Example: { "intro": <DialogueLine>, "ask_quest": <DialogueLine> }
@export var lines: Dictionary = {}
## ID of the first line to display when dialogue starts.
@export var start_line_id: String = ""
## Convenience accessor — returns null for unknown IDs.
func get_line(id: String) -> DialogueLine:
return lines.get(id, null)
C#
// DialogueData.cs
using Godot;
using Godot.Collections;
[GlobalClass]
public partial class DialogueData : Resource
{
/// <summary>Maps line ID strings to DialogueLine resources.</summary>
[Export] public Dictionary Lines { get; set; } = new();
/// <summary>ID of the first line to display when dialogue starts.</summary>
[Export] public string StartLineId { get; set; } = "";
/// <summary>Returns the DialogueLine for id, or null if not found.</summary>
public DialogueLine GetLine(string id)
{
if (Lines.ContainsKey(id))
return Lines[id].As<DialogueLine>();
return null;
}
}
インスペクターで
linesにエントリーを追加し、文字列キーとDialogueLineリソースの値を持つ Dictionary を設定します。または、JSON からプログラムで読み込むこともできます(7章を参照)。
4. DialogueManager
シングルトンのオートロードがアクティブな DialogueData を管理し、現在の行を追跡します。start_dialogue(data) はデータを設定して最初の行を発行し、advance() は次に進み、choose(choice_index) は選択肢を選びます。シグナル:dialogue_started、line_displayed(line)、choice_presented(choices)、dialogue_ended。
GDScript と C# による完全なマネージャー(行の移動、選択肢の処理、条件評価フック、シグナル)については、references/dialogue-manager.md を参照してください。
5. 分岐と条件
選択肢は DialogueLine.choices(Dictionary の Array)に格納されます。各選択肢には text、next_line_id、省略可能な condition があります。条件は Expression クラスで評価される式文字列で、プロジェクトの状態(例:GameState オートロード)は名前付き入力として渡します。
選択肢処理と条件評価器の完全な実装(GDScript + C#)、および Expression の入力に関するセキュリティ上の注意点については、references/branching-and-conditions.md を参照してください。
6. 会話 UI
行の本文用の RichTextLabel(BBCode を有効化)、話者名用の Label、選択肢ボタン用の VBoxContainer を備えた CanvasLayer を使用します。Timer で制御する RichTextLabel.visible_characters により、タイプライター効果を実現します。UI は DialogueManager のシグナルを購読します。
シーンツリーの断片、タイプライター効果の実装方法、選択肢ボタンの生成、GDScript と C# による完全な接続方法については、references/ui-presentation.md を参照してください。
7. 外部フォーマット
デザイナーが編集しやすいよう、JSON から会話を読み込みます。読み込み時に JSON のキーを DialogueLine のプロパティに対応付けます。または、ノードグラフエディターを使える Dialogic アドオンを統合します(コミュニティ標準)。
JSON ローダーの実装方法と Dialogic の統合に関する注意事項については、references/external-formats.md を参照してください。
8. 変数の埋め込み
会話テキストでは、{player_name} 形式のプレースホルダーを使用できます。簡単なテンプレート処理で解決します。GDScript では text.format(vars) を使い、C# ではプレースホルダーごとに string.Replace を使います。
GDScript と C# の埋め込み用ヘルパーについては、references/variable-interpolation.md を参照してください。
9. 実装チェックリスト
-
DialogueLineとDialogueDataはResourceを継承し、インスペクター連携のために[GlobalClass](C#)を指定します -
DialogueManagerは Autoload として登録され、すべてのシーンで単一のインスタンスを共有します -
start_dialogue()はdialogue_dataにアクセスする前に、null でないことをアサートします -
advance()は、選択肢が保留中の場合に呼び出されないようガードします -
choose()は、生のchoices配列ではなく、フィルター済みの表示可能な選択肢リストを操作します - 条件文字列では、安定した Autoload メソッド名のみを参照します。シーン固有のノードは参照しないでください
-
_evaluate_condition()はGameStateをExpressionの入力名として登録します(parse(cond, ["GameState"])、execute([GameState]))。Expressionは Autoload 名を解決しません - タイプライターのタイマーでは、BBCode との互換性のため、フレームごとの文字列スライスではなく
visible_charactersを使用します - タイプライターの動作中に
ui_acceptを押すと全文を表示し、もう一度押すと次の行に進みます - 新しい選択肢ボタンを作成する前に、既存のボタンを解放(
queue_free)します。古い子ノードを蓄積させないでください - JSON ローダーはファイルを開く処理と解析処理を個別に検証し、それぞれの失敗について明確なエラーメッセージを出力します
- 変数の補間は
_interpolate()ヘルパーに一元化し、シグナルハンドラーに分散させません -
next_line_id = ""は会話の終了を示します。空文字列以外の特殊なセンチネル文字列は使用しません -
push_error()のすべてのメッセージに、ログを追跡しやすいようクラス名とメソッド名を含めます