<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>叙事系统 on 蜂窝</title><link>https://yufenghuang.tech/tags/%E5%8F%99%E4%BA%8B%E7%B3%BB%E7%BB%9F/</link><description>Recent content in 叙事系统 on 蜂窝</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><managingEditor>yufenghuang009@gmail.com (Evan Wong)</managingEditor><webMaster>yufenghuang009@gmail.com (Evan Wong)</webMaster><copyright>EvanWong</copyright><lastBuildDate>Mon, 12 Oct 2026 09:30:00 +0800</lastBuildDate><atom:link href="https://yufenghuang.tech/tags/%E5%8F%99%E4%BA%8B%E7%B3%BB%E7%BB%9F/index.xml" rel="self" type="application/rss+xml"/><item><title>HeirCut 开发手记（四）：把客人说的话剪下来</title><link>https://yufenghuang.tech/p/heircut-devlog-word-swap/</link><pubDate>Mon, 12 Oct 2026 09:30:00 +0800</pubDate><author>yufenghuang009@gmail.com (Evan Wong)</author><guid>https://yufenghuang.tech/p/heircut-devlog-word-swap/</guid><description>&lt;blockquote&gt;
&lt;p&gt;「HeirCut 开发手记」第四篇。游戏简介见&lt;a class="link" href="https://yufenghuang.tech/p/heircut-devlog-submit-guidance/" &gt;第一篇&lt;/a&gt;文末。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;《宫廷理发师》的点子，是主策划在理发的时候想到的：理发师总爱和客人聊这聊那。那如果理发师能把客人说过的话「剪」下来，再拼进别人的话里呢？&lt;/p&gt;
&lt;p&gt;这就是游戏的核心玩法——换词。客人说话时，有些词可以用剪刀剪下来，收进笔记本；有些句子里留着一个可以替换的位置，把笔记本里的词拖进去，说话的人就会顺着新的意思说下去，剧情也跟着改变。&lt;/p&gt;
&lt;p&gt;这篇记录换词是怎么实现的、换进去的词怎么一路影响到结局，以及设计上我们一直在纠结的取舍。&lt;/p&gt;
&lt;h2 id="一个例子"&gt;&lt;a href="#%e4%b8%80%e4%b8%aa%e4%be%8b%e5%ad%90" class="header-anchor"&gt;&lt;/a&gt;一个例子
&lt;/h2&gt;&lt;p&gt;第一天的女巫来烫发。她说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;只有湿冷的环境，头发才不容易烫伤。可惜，现在是&lt;strong&gt;正午&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;「正午」是一个可以替换的位置。如果玩家把之前从公主那里剪下来的「晚上」换进去，女巫会说「你真走运，夜晚是最佳的烫发时机」，烫发就不会把她的头发烫焦；如果换进去的是别的词，她会说「抱歉，我刚刚似乎失言了，请忘掉吧」，一切照旧。&lt;/p&gt;
&lt;p&gt;整套机制就是这个循环的重复：&lt;strong&gt;听 → 剪 → 换 → 看它变成现实。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="一句话是一串小块"&gt;&lt;a href="#%e4%b8%80%e5%8f%a5%e8%af%9d%e6%98%af%e4%b8%80%e4%b8%b2%e5%b0%8f%e5%9d%97" class="header-anchor"&gt;&lt;/a&gt;一句话是一串小块
&lt;/h2&gt;&lt;h3 id="富文本不够用"&gt;&lt;a href="#%e5%af%8c%e6%96%87%e6%9c%ac%e4%b8%8d%e5%a4%9f%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;富文本不够用
&lt;/h3&gt;&lt;p&gt;最开始考虑过直接用 TextMeshPro 的富文本：给可剪的词加个标签、上个颜色。但我们要的不只是「显示得不一样」：每个词要能单独点击、能被剪走、剪走后留下一个同样宽度的空位、空位要能接住拖进来的词，换进去的词长短不同还要重新排版。&lt;/p&gt;
&lt;p&gt;富文本做不到这些，于是改成了&lt;strong&gt;把一句话拆成一串小块&lt;/strong&gt;：普通文字是一块，每个可剪的词是一块独立的可交互对象，它们放在一个会自动换行的布局里，看起来就像一句完整的话。&lt;/p&gt;
&lt;p&gt;建库第一周的版本就是这样做的。台词里用标签标出可剪的词，大致是这样（示意）：&lt;/p&gt;
&lt;div class="code-block" data-lang="text"&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;今晚是公主的大婚，为我&amp;lt;demand type=&amp;#34;Curl&amp;#34;&amp;gt;烫&amp;lt;/demand&amp;gt;一个属于&amp;lt;clue id=&amp;#34;…&amp;#34;&amp;gt;巫女&amp;lt;/clue&amp;gt;教母的发型。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;解析器把它拆成「文字块 + 词块」，词被剪掉时，原位置换成一个等宽的空槽：&lt;/p&gt;
&lt;div class="code-block" data-lang="csharp"&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 第一版：剪下一个词，原位置换成同样宽度的空槽&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;CutKeyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Keyword&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ClueBook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddClue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClueID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;slot&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slotPrefab&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dialogContainer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetSiblingIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetSiblingIndex&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LayoutElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;preferredWidth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LayoutElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;preferredWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;「把话剪下来」这个比喻，从第一版代码就在了——它和理发用的是同一把剪刀。&lt;/p&gt;
&lt;h3 id="现在的写法"&gt;&lt;a href="#%e7%8e%b0%e5%9c%a8%e7%9a%84%e5%86%99%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;现在的写法
&lt;/h3&gt;&lt;p&gt;后来剧情改成由内容驱动（见&lt;a class="link" href="https://yufenghuang.tech/p/heircut-devlog-encounter-refactor/" &gt;第三篇&lt;/a&gt;），台词里不再直接写数字 ID，而是用占位符引用有名字的槽和词：&lt;/p&gt;
&lt;div class="code-block" data-lang="json"&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;我能做的，也仅仅是在婚礼上{slot.king.vow}……然后告诉百姓，{slot.king.peace}。&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tokens&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;tokenType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ReplacementSlot&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;slotId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;slot.king.vow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;defaultTextKey&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;text.token.king.vow.default&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;tokenType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ReplacementSlot&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;slotId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;slot.king.peace&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;defaultTextKey&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;text.token.king.peace.default&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;运行时再把它翻译回旧的标签格式，交给原来的解析和显示代码。显示层基本没动，换掉的只是「词从哪里来」。&lt;/p&gt;
&lt;h2 id="换进去的词怎么改变剧情"&gt;&lt;a href="#%e6%8d%a2%e8%bf%9b%e5%8e%bb%e7%9a%84%e8%af%8d%e6%80%8e%e4%b9%88%e6%94%b9%e5%8f%98%e5%89%a7%e6%83%85" class="header-anchor"&gt;&lt;/a&gt;换进去的词，怎么改变剧情
&lt;/h2&gt;&lt;h3 id="每个槽有一张候选表"&gt;&lt;a href="#%e6%af%8f%e4%b8%aa%e6%a7%bd%e6%9c%89%e4%b8%80%e5%bc%a0%e5%80%99%e9%80%89%e8%a1%a8" class="header-anchor"&gt;&lt;/a&gt;每个槽有一张候选表
&lt;/h3&gt;&lt;p&gt;每个槽在内容里登记了一组&lt;strong&gt;候选词&lt;/strong&gt;。比如国王上面那句话的两个槽：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;槽&lt;/th&gt;
&lt;th&gt;默认&lt;/th&gt;
&lt;th&gt;候选&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;婚礼上要做的事&lt;/td&gt;
&lt;td&gt;宣读誓词&lt;/td&gt;
&lt;td&gt;离开；把婚约撕个粉碎&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;告诉百姓的话&lt;/td&gt;
&lt;td&gt;这门婚约将带来和平&lt;/td&gt;
&lt;td&gt;我对狗毛过敏&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;玩家确认之后，卷轴烧掉、重新长出一句换好的话；按下一句时，这次替换才真正提交，去匹配剧情规则。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两个槽同时换成「把婚约撕个粉碎」和「我对狗毛过敏」，国王会走向「反抗」这条线，婚礼被推迟，第一天才能往下走。&lt;/li&gt;
&lt;li&gt;只把第一个槽换成「离开」，国王会走另一条线；这个选择还会一直影响到第二天公主有没有出逃的念头。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="只有一条路通向结局"&gt;&lt;a href="#%e5%8f%aa%e6%9c%89%e4%b8%80%e6%9d%a1%e8%b7%af%e9%80%9a%e5%90%91%e7%bb%93%e5%b1%80" class="header-anchor"&gt;&lt;/a&gt;只有一条路通向结局
&lt;/h3&gt;&lt;p&gt;换词能影响很多东西：客人接下来说什么、后面播哪段演出、这次会面怎么收尾。但真正能影响&lt;strong&gt;结局&lt;/strong&gt;的，只有一条路：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yufenghuang.tech/p/heircut-devlog-word-swap/word-to-ending.svg"
loading="lazy"
alt="换进去的词如何影响结局：候选词被换进槽 → 如果这个候选会「打勾」，就记进账本 → 账本投影成故事事实 → 当天结算读取故事事实，决定走向哪一天或哪个结局"
&gt;&lt;/p&gt;
&lt;p&gt;一个词换进去，如果它在候选表里被标成「打勾」，就会记进笔记本的账本；账本被投影成一组&lt;strong&gt;故事事实&lt;/strong&gt;；每天结束时，结算只读这些故事事实。&lt;/p&gt;
&lt;p&gt;这个限制是被一次测试逼出来的。我们用编辑器加过一个测试用的第四天，在客人的会面里用「设置事实」记下「玩家是否起疑」。推演器显示所有规则都能触发，可两个结局里有一个怎么都到不了——因为会面里设置的事实，在会面结束后就没了，结算根本看不到它。改成由换词打勾来推导之后，立刻就通了。&lt;/p&gt;
&lt;p&gt;还有一个后来才分清的概念：&lt;strong&gt;「登记为候选」和「换进去会打勾」是两件事。&lt;/strong&gt; 一开始两者是绑在一起的，后来专门加了一个开关把它们拆开：有些候选是给将来的路线预留的，现在换进去不会改变任何东西。&lt;/p&gt;
&lt;h2 id="设计上的取舍"&gt;&lt;a href="#%e8%ae%be%e8%ae%a1%e4%b8%8a%e7%9a%84%e5%8f%96%e8%88%8d" class="header-anchor"&gt;&lt;/a&gt;设计上的取舍
&lt;/h2&gt;&lt;h3 id="自由度和工作量"&gt;&lt;a href="#%e8%87%aa%e7%94%b1%e5%ba%a6%e5%92%8c%e5%b7%a5%e4%bd%9c%e9%87%8f" class="header-anchor"&gt;&lt;/a&gt;自由度和工作量
&lt;/h3&gt;&lt;p&gt;我们希望玩家放下一个词的时候，是真心期待「它会怎么变成现实」。可每多一个能被接住的词，就要多写一段回应、多一条规则、多一次测试。&lt;/p&gt;
&lt;p&gt;现在的内容里一共有 13 个槽、20 个候选词。换句话说，大部分槽只有一两个词会被「接住」。为了不让剩下的词显得无效，我们做了几件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;错词也有回应。&lt;/strong&gt; 换进候选之外的词，客人会自己圆回去（「抱歉，我刚刚似乎失言了」），剧情照常继续，而不是直接拒绝玩家的操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有些槽只是为了参与感。&lt;/strong&gt; 国王问「这是……{谁}给你的？」，这个槽不影响路线，也不影响后面的对话，只是让玩家在关键时刻有手可动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错词不能把客人卡住。&lt;/strong&gt; 如果换进去的词没有任何规则接住，客人就会停在那里。所以每句带槽的话都要留一个「默认往下走」的出口；编辑器里的换词向导会自动把它补上。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="正确的词和好玩的词"&gt;&lt;a href="#%e6%ad%a3%e7%a1%ae%e7%9a%84%e8%af%8d%e5%92%8c%e5%a5%bd%e7%8e%a9%e7%9a%84%e8%af%8d" class="header-anchor"&gt;&lt;/a&gt;「正确的词」和「好玩的词」
&lt;/h3&gt;&lt;p&gt;更难的是另一个问题：我们到底希望玩家多换词、多试，还是只有换对了才算「正确」？&lt;/p&gt;
&lt;p&gt;如果只有一个正确答案，换词就变成了填空题，会有点无趣。我们的做法是特意放进一些天马行空的候选——「我对狗毛过敏」「开门见山」——让玩家在荒诞里找到乐趣。这种荒诞感是我们想要的，但也是最难想到的。用策划陈2333 的话说：这主要靠对脑电波。&lt;/p&gt;
&lt;p&gt;这个问题到现在也没有完全解决。&lt;/p&gt;
&lt;h3 id="需求词另一种收集"&gt;&lt;a href="#%e9%9c%80%e6%b1%82%e8%af%8d%e5%8f%a6%e4%b8%80%e7%a7%8d%e6%94%b6%e9%9b%86" class="header-anchor"&gt;&lt;/a&gt;需求词：另一种收集
&lt;/h3&gt;&lt;p&gt;除了线索词，客人话里还有&lt;strong&gt;需求词&lt;/strong&gt;，它们决定这次理发要做什么。需求词和线索词一样是剪下来的，但用法不同：玩家要把两个需求词放进合成板，合成出一个服务。比如国王的「手握王权」加「俯视众生」，合成「鹰翼」，这是对的；换成「手握王权」加「盘旋」，合成的是「蛇纹」，国王会不高兴。&lt;/p&gt;
&lt;p&gt;需求词和合成板都是最初策划案里就有的循环，合成板长什么样是后来讨论出来的。实现上有一个容易被「修」坏的设计：**需求词属于玩家，不属于客人。**第三天的二公主要代替公主去联姻，她的需求就要用第一天从公主那里收来的词去合成。代码里查「有没有这个需求词」是跨角色的，这是故意的。&lt;/p&gt;
&lt;h2 id="几个实现上的坑"&gt;&lt;a href="#%e5%87%a0%e4%b8%aa%e5%ae%9e%e7%8e%b0%e4%b8%8a%e7%9a%84%e5%9d%91" class="header-anchor"&gt;&lt;/a&gt;几个实现上的坑
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;拖到哪个槽，由词说了算。&lt;/strong&gt; 玩家拖词时瞄的是鼠标指针，但词是以指针为中心画出来的，两者对不上。后来改成「槽的中心落在被拖的词里面」，指针只用来打破平局；高亮和放下用的是同一个判断，免得高亮了一个槽，放下时却去了另一个。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;挡住「跳过」的是状态，不是按钮。&lt;/strong&gt; 带槽的句子在换词完成前不能跳过。最早的做法是把「下一句」按钮藏起来，结果空格键和点击跳过照样能过。后来把这个判断挪到了推进对话的地方。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读档后需求词被算了两遍。&lt;/strong&gt; 一句话里有几个需求词没收集，就不让往下走。读档重新显示这句话时，已经收集过的词又被算回去了，而它已经点不动了，对话框就一直晃、游戏卡死。之前没出事，是因为玩家能重复收集同一个词，正好把计数凑平——&lt;strong&gt;一个缺陷在掩盖另一个缺陷&lt;/strong&gt;，堵掉前者就暴露了后者。修法是让「显示成已收集」和「计数」共用同一个判断。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;词拿出来再放回去，要回到原来那一页。&lt;/strong&gt; 笔记本按天、按客人分页。词被拖进槽、又撤回时，最初是按「当天 + 当前客人」算页的，结果跨天复用的词会回到一个根本不存在的页。现在是从哪一页拿的，就回哪一页。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="还没解决的"&gt;&lt;a href="#%e8%bf%98%e6%b2%a1%e8%a7%a3%e5%86%b3%e7%9a%84" class="header-anchor"&gt;&lt;/a&gt;还没解决的
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;「正确的词」和「好玩的词」之间的平衡&lt;/strong&gt;，还在调。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;候选词是写死的。&lt;/strong&gt; 更多的候选意味着更多的手写回应。我们讨论过让 AI 来判断一个任意的词放进来「说不说得通」，并想好了边界：AI 只能在作者写好的几种结果里选，不能凭空创造剧情事实，超时就退回写好的文本，结果和存档一起保存，读档时不重新问。但这目前只停留在计划里。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="回头看"&gt;&lt;a href="#%e5%9b%9e%e5%a4%b4%e7%9c%8b" class="header-anchor"&gt;&lt;/a&gt;回头看
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;一个词就是一个对象。&lt;/strong&gt; 放弃富文本、把句子拆成一串可交互的小块，是这套玩法能做下去的前提。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;换词能影响的东西很多，但通向结局的只有一条路。&lt;/strong&gt; 这条限制一开始是踩坑踩出来的，后来反而成了内容作者最好理解的一条规则。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自由度要有兜底。&lt;/strong&gt; 错词有回应、没被接住的词不卡人、有些槽只为参与感——这些都是为了让「随便试试」不会被惩罚。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最难的部分不在代码里。&lt;/strong&gt; 想出「我对狗毛过敏」这样的词，比实现它难得多。&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>