mcpField
D
dialogue-systems

dialogue-systems

github.com/gamedev-skills开发5.4k7.5k 次安装1 天前更新
代码仓库

关于 dialogue-systems

面向游戏叙事设计者和开发者的对话系统技能,介绍如何构建分支对话、选择条件与叙事状态。涵盖 Ink、Yarn Spinner 和自定义数据驱动运行器的选择与接入。

主要功能

  1. 01比较 Ink、Yarn Spinner 与自定义方案
  2. 02设计节点、选项和条件分支
  3. 03管理对话变量与状态
  4. 04使用行 ID 支持本地化
  5. 05将运行器接入游戏循环

适用场景

  1. 01设计带条件选项的分支对话
  2. 02选择适合项目的对话创作工具
  3. 03将台词、选项和命令接入游戏流程
  4. 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。

核心工作流

  1. 选择创作方式。
    • Ink —— 以文本为先,方便编剧,采用 weave/gather 流程;非常适合 对话密集型或选择驱动的叙事。通过 ink runtime / inkle 插件集成。
    • Yarn Spinner —— 基于节点,使用明确的 <<commands>>,适合引擎钩子 较多、由游戏驱动的对话。
    • 自定义运行器 —— 当你需要完全控制或尽量减少依赖时,使用 JSON/资源图 和小型解释器。不要构建一种语言,而要构建一张图。
  2. 定义节点约定。 一个节点会产生以下内容之一:一行台词(说话者 + 文本)、 一组选项、命令/副作用,或结束/跳转。运行器会遍历节点,并将台词/选项交给 UI。
  3. 将变量与流程分开。 保留一个变量存储区(布尔值、数字、字符串),供对话读取/ 写入;使用基于这些变量的条件控制选项。
  4. 从一开始就支持本地化。 使用台词 ID而非原始字符串进行创作,让显示文本 来自按语言区域设置为键的字符串表。
  5. 由游戏循环驱动。 运行器是一个状态机:current 节点 → 发出内容 → 等待输入(继续或选择)→ 前进。
  6. 逐一检查分支。 测试每条选项路径;确认条件、变量写入正确,且每条分支都会到达 结束节点或有效跳转目标。

模式

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 — 与此技能结合使用的游戏类型。

评论

支持 Markdown