全部文章

断头节点与不可达节点:对话树检查器证得了什么、证不了什么

对话树的失败里有两类机器能判死,一类不能;分清楚它们,你才知道注意力该花在哪。

发布于

对话树的失败方式就那么几种,而值得把话说准的是:哪些工具替你判得了。 答案不是“全部”,也不是“一个都不能”。

能判死的那两类

对话树有两类失败是机器能完全判死的:断头节点是没有任何出边、又没被标为终止的节点; 不可达节点是从任何入口都走不到的节点。两者都是普通的图论问题,一遍就能判完, 而且都不依赖品味。检查器判不了的是——一个可达的节点,在玩家真正所处的状态下 是不是还可达;那要求对每条边上的 flag 条件做推理,是另一个难得多的问题。

断头节点在实机里表现为:对话停住了,没有任何离开的办法—— 玩家卡在对话镜头里,没有选项。它几乎总是编辑引入的: 某个节点原本有两个回复,改稿时砍掉一个,而剩下的那个正好是被挪去别处的那条分支。

不可达节点是反过来的,而且常见得多。有人写了一条分支,又重构了它上面的对话, 于是那条分支还在文件里,没有任何东西指向它。没人会注意到, 因为这种失败的形态是缺席:永远不出现的内容,和从没被写过的内容长得一模一样。 但代价是实的——它被写了、被审了,可能还配了音,然后什么也没做。

不属于同一类的那一个

问“在 flag 条件下这个节点可不可达”,你就已经离开图论了。边上挂着对游戏状态的条件, 一组条件能不能同时满足,取决于游戏里还有什么会设置那些 flag、按什么顺序、受什么约束。

软锁就在这一类里——玩家走到某个状态,某段必需的对话再也触发不了。 这确实难,而且正是形式化方法真能挣到饭吃的地方。 如果你要的是证明而不是抽样,你要的是一个求解器; Yarn Spinner 那边在这个方向上有很认真的工作在推进。

我们不去那儿比。我们把图论可判的那两类做完整, 把任务读写的每一个 flag 都登记下来(至少让状态是可枚举的), 再用模拟通玩去抽样状态空间——而不是声称自己证明了它。

谁的检查器都判不了的那两类

还有两种失败要紧,而且完全不机械:

  • 可达但没有意义的分支。 三个选项汇到同一个下一节点,中间不改变任何状态。 结构上完美;对玩家是一次撒谎。判据是这几条分支改变的东西有没有区别, 而那是设计判断。
  • 角色说话不像自己。 结构上完全看不见。这正是声音圣经值得在生成对话之前 就写下来的理由:一个定好的语域、一组口头禅、一份“这个角色绝不会用的词”清单, 能给审阅者一个可对照的东西,而不是“总觉得哪里不对”。

注意力该花在哪

把能判死的那两类自动化掉,然后别再想它们——它们检查起来很便宜、会没完没了地复发, 而每一小时手工找它们的时间,都是没花在那两类需要你的问题上的时间。 对依赖状态的那一类要有意识地抽样,而不是指望测试碰巧覆盖到。 省下来的注意力花在“这些分支到底有没有意义”上,因为那一部分,没有任何东西会替你做。