关于 dialogue-systems
面向游戏叙事设计者和开发者的对话系统技能,介绍如何构建分支对话、选择条件与叙事状态。涵盖 Ink、Yarn Spinner 和自定义数据驱动运行器的选择与接入。
主要功能
- 01比较 Ink、Yarn Spinner 与自定义方案
- 02设计节点、选项和条件分支
- 03管理对话变量与状态
- 04使用行 ID 支持本地化
- 05将运行器接入游戏循环
适用场景
- 01设计带条件选项的分支对话
- 02选择适合项目的对话创作工具
- 03将台词、选项和命令接入游戏流程
- 04检查分支路径与状态变更
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill dialogue-systems安装后在 Claude Code 中输入/dialogue-systems确认已加载。
附带文件references/ink-and-yarn.mdreferences/runner.md
详细介绍
对话系统
将对话建模为一个图:节点保存台词,选项负责分支,条件控制选项,变量则记录玩家做过的事。首先要做出的真正决定是自建还是购买——采用成熟的创作工具(Ink 或 Yarn Spinner),还是编写一个小型数据驱动运行器。此技能涵盖 Ink 和 Yarn;visual-novel 和 rpg 类型会使用它。
适用场景
- 用于设计分支对话、选项菜单或会影响后续对话的叙事状态(标记、关系值)。
- 用于在 Ink、Yarn Spinner 和自定义 JSON/资源格式之间做出选择。
- 用于将对话脚本接入游戏循环(推进台词、呈现选项、运行命令、解析变量)。
不适用场景: 对于引擎 UI(文本框、肖像、选项按钮),请使用
godot-ui-control 或引擎的 UI 技能。对于跨会话持久化叙事变量,请使用
save-systems。对于 Godot/Unity 中以资源形式存储的数据,请参阅
godot-resources / unity-scriptableobjects。
核心工作流
- 选择创作方式。
- Ink —— 以文本为先,方便编剧,采用 weave/gather 流程;非常适合 对话密集型或选择驱动的叙事。通过 ink runtime / inkle 插件集成。
- Yarn Spinner —— 基于节点,使用明确的
<<commands>>,适合引擎钩子 较多、由游戏驱动的对话。 - 自定义运行器 —— 当你需要完全控制或尽量减少依赖时,使用 JSON/资源图 和小型解释器。不要构建一种语言,而要构建一张图。
- 定义节点约定。 一个节点会产生以下内容之一:一行台词(说话者 + 文本)、 一组选项、命令/副作用,或结束/跳转。运行器会遍历节点,并将台词/选项交给 UI。
- 将变量与流程分开。 保留一个变量存储区(布尔值、数字、字符串),供对话读取/ 写入;使用基于这些变量的条件控制选项。
- 从一开始就支持本地化。 使用台词 ID而非原始字符串进行创作,让显示文本 来自按语言区域设置为键的字符串表。
- 由游戏循环驱动。 运行器是一个状态机:
current节点 → 发出内容 → 等待输入(继续或选择)→ 前进。 - 逐一检查分支。 测试每条选项路径;确认条件、变量写入正确,且每条分支都会到达 结束节点或有效跳转目标。
模式
1. 与引擎无关的对话图(数据,而非代码)
{
"start": "guard_intro",
"nodes": {
"guard_intro": {
"speaker": "Guard", "line": "DLG_GUARD_001",
"choices": [
{ "text": "DLG_OPT_BRIBE", "to": "bribe", "if": "gold >= 50" },
{ "text": "DLG_OPT_LEAVE", "to": "end" }
]
},
"bribe": {
"speaker": "Guard", "line": "DLG_GUARD_BRIBED",
"set": { "gate_open": true, "gold": "gold - 50" },
"next": "end"
},
"end": { "end": true }
}
}
line/text 是字符串表 ID(用于本地化),而不是文本字面值。if
用于控制选项;set 会修改变量存储区。遍历此图的完整解释器见
references/runner.md。
2. 运行器步骤(在图上运行的状态机)
# The runner holds the current node and a variable store; the UI calls advance().
func present(node):
if node.has("line"):
ui.show_line(node.speaker, localize(node.line))
if node.has("choices"):
var shown = node.choices.filter(func(c): return eval_cond(c.get("if", "")))
ui.show_choices(shown) # only choices whose condition passes
func choose(choice): # called when the player clicks a choice
apply_set(choice.get("set", {})) # write variables
goto(choice.to)
func goto(id):
current = graph.nodes[id]
apply_set(current.get("set", {}))
if current.get("end", false): ui.close(); return
present(current)
if current.has("next") and not current.has("choices"):
goto(current.next) # auto-advance linear nodes
3. Ink —— 使用 knots、选项和变量实现分支(inkle)
// Ink: '*' = once-only choice, '+' = sticky. [bracketed] text shows only in the
// choice, not the printed result. '->' diverts; '-> END' stops the flow.
VAR gold = 60
=== guard_intro ===
The guard blocks the gate.
* {gold >= 50} [Offer 50 gold] "Here, take it."
~ gold = gold - 50
The guard pockets it and steps aside. -> END
* [Leave] You turn back. -> END
Ink 会追踪每个 knot 被访问的次数,因此 {visited_knot} 是内置条件。
变量可以是全局变量(VAR),也可以是临时变量(~ temp)。
4. Yarn Spinner —— 节点、选项和命令(Yarn Spinner 3.x)
title: GuardIntro
---
<<declare $gold = 60>>
<<declare $gate_open = false>>
Guard: You can't pass.
-> Offer 50 gold <<if $gold >= 50>>
<<set $gold = $gold - 50>>
Guard: ...fine. Go on through.
<<set $gate_open to true>>
-> Leave
Guard: Good choice.
===
Yarn 台词可以以 Speaker: 开头;选项使用 ->;<<set>>/<<declare>>
用于管理 $variables;<<if>> 用于控制选项;<<jump NodeName>> 用于在节点之间
跳转。在文本中使用 {$gold} 插入变量值。每个变量都应在首次使用前声明:未声明的变量
仍可编译(Yarn 会推断其类型,并赋予零/false/空的初始值),但这会掩盖拼写错误。
这些构造与 Yarn Spinner 2.x 中的内容一致。
常见问题
- 硬编码显示文本而不是使用行 ID 会让本地化变成重写工作。从第一天起就基于字符串表进行创作。
- 为简单的分支树发明一种脚本语言。如果你只需要台词、选项和标志,使用 JSON/资源图加上 50 行的运行器,胜过必须维护的解析器。需要真正的流程控制时,使用 Ink/Yarn。
- 变量与 UI 耦合:单独存储叙事状态,这样同一段对话就能用于过场动画、菜单和测试。通过
save-systems持久化。 - 无法到达或没有后续的节点:没有
next、选项或结束标记的节点会悄无声息地卡住。验证每个节点都会结束或分支。 - 在玩家可以重复访问的台词节点中修改状态会导致重复应用(
gold被扣两次)。在状态转换时应用set,或使用已查看标志进行保护。 - 意外混用 Ink 的
*(仅一次)和+(持续有效):循环菜单需要使用持续有效的+选项,否则选项在使用一次后就会消失。
参考资料
references/ink-and-yarn.md— 并列语法速查表(选项、跳转/转移、变量、条件、包含)和集成说明。references/runner.md— 完整的自定义对话运行器:图结构、条件/表达式求值、变量存储和本地化查询。
相关技能
save-systems— 持久化叙事变量和已查看标志。godot-resources、unity-scriptableobjects— 将对话存储为引擎数据。godot-ui-control— 呈现文本框、肖像和选项按钮。visual-novel、rpg— 与此技能结合使用的游戏类型。