打字机效果看似简单,节奏很容易错
剧情对话里常见逐字显示:文字一个个出现,配合语音、头像、音效和选项。Godot 用 RichTextLabel 很容易做出基础效果,调 visible_characters 就能逐字出现。但真正上线后,边界很多:玩家点击是加速还是跳到末尾,语音如何同步,富文本标签怎么算字符,选项什么时候出现,翻译变长后速度怎么调。
对话打字机效果的目标是节奏,而不是炫技。它要让玩家能舒服阅读,想跳过时不受阻,重要信息不丢,语音和文字不打架。
stateDiagram-v2
[*] --> LoadingLine
LoadingLine --> Typing: 文本和语音准备完成
Typing --> Completed: 字符显示完毕
Typing --> Completed: 玩家点击跳到末尾
Completed --> WaitingInput: 等待继续/显示选项
WaitingInput --> LoadingLine: 下一句
WaitingInput --> [*]: 对话结束
RichTextLabel 的字符计数要小心
RichTextLabel 支持 BBCode,文本里可能有颜色、图标、变量。逐字显示时,不能把标签本身当成可见字符。Godot 的 visible_characters 可以处理可见字符,但复杂标签、图片和自定义效果仍要测试。
变量替换应在开始打字前完成。玩家名、道具名、按键图标都替换成最终文本,再计算显示长度。否则打字过程中插入变量,会造成跳动。
如果文本包含等待标记,比如 [pause=0.3],需要自己的解析层,把它转换成节奏控制,而不是直接交给 RichTextLabel。标记不应显示给玩家,也要给翻译团队说明用法。
点击逻辑要符合直觉
玩家点击对话时,通常第一次点击让当前句立刻显示完整,第二次点击进入下一句。不要第一次点击直接跳过整句,除非玩家长按或开启快速跳过。这个规则要稳定,不同对话不要不同。
自动播放模式下,文本显示完毕后等待语音结束或最短阅读时间,再进入下一句。玩家手动点击可以打断等待。跳过剧情则是更高层操作,需要确认是否跳过整段。
输入上下文也要处理。对话打开时,确认键用于推进文字,不应该同时触发场景交互或攻击。关闭对话后恢复 gameplay 输入。
语音同步和无语音回退
有语音时,打字速度可以参考语音长度。短句不要打得比语音慢太多,长句也不要因为语音快而让文字飞过去。可以设基础字符速度,再根据语音长度微调,保证可读。
玩家点击补全文字时,语音是否继续?通常继续播放,除非进入下一句时停止当前语音。快速跳过整段剧情时,语音要停止或淡出。AudioService 和 DialogueSystem 要协作,不要各管各的。
没有语音或语音下载失败时,对话仍然可用。系统按文本长度和语言设置阅读时间。语音是增强,不是对话流程的硬依赖。
选项出现要等文本完成
分支选项不应在句子还没显示完时就出现,除非设计需要。通常当前句完成后,选项淡入,玩家再选择。选项文本也可能很长,布局要支持多行和滚动。
选项的可用条件和提交逻辑属于对话系统,不属于打字机效果。但打字机需要知道何时交出控制权。文本完成 -> 显示选项 -> 等待选择,这是清晰边界。
历史记录也要记录完整文本,而不是逐字状态。玩家打开对话历史时,应看到已经显示过的完整句子、说话者和选择结果。
本地化影响节奏
中文、英文、德语、日文长度差异很大。固定每秒 30 字符不一定合适。可以按语言设置速度,或者按“预计阅读时间”计算。标点停顿也要本地化,中文逗号和英文逗号可能使用同一规则,但日文和泰文需要测试。
富文本标签不要交给翻译随意改。若需要强调词,可以提供受控标签。翻译错误的标签会破坏打字显示,导入时要校验标签成对和白名单。
小结
Godot 对话打字机效果要把显示、输入、语音、选项和本地化节奏合在一起设计。RichTextLabel 提供基础显示,DialogueSystem 管状态,AudioService 管语音,输入上下文保护推进逻辑。打字机做得好,玩家感受到的是自然叙事;做得粗糙,就会变成不断误跳的文字框。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
我会给对话系统准备一组测试文本:富文本、变量、长翻译、无语音、有语音、选项、暂停标记。每次改打字机逻辑都跑这组文本,能避免剧情上线后才发现节奏错。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。