尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Flame 对话引擎 `<<wait>>` 命令详解:Jenny 脚本中的暂停与时间控制
Flame 对话引擎wait命令详解Jenny 脚本中的暂停与时间控制【免费下载链接】flameA Flutter based game engine.项目地址: https://gitcode.com/GitHub_Trending/fl/flamewait是 Flame 内置 Jenny 对话引擎YarnSpinner 语言的 Dart 移植实现提供的内置命令用于让对话流程暂停指定的秒数后再继续执行。本文以 wait.md 文档为核心结合 wait_command.dart 源码实现与 wait_command_test.dart 测试用例完整讲解其语法、参数约束、底层实现原理、典型应用场景与常见错误排查帮助你写出节奏可控、时间精确的对话脚本。wait命令的作用与定位在 Jenny 的对话体系中.yarn文件中的脚本由节点node、行line、选项option与命令command组成其中命令是夹在双层尖括号与之间的特殊指令详见 commands.md。wait属于内置命令在 commands.md 中被归类到控制流Control flow分组官方描述为Pauses the dialogue for the specified amount of time.它的核心作用是让对话引擎暂停指定的时长单位秒之后再恢复执行后续对话内容。这个能力在游戏对话中非常实用例如角色说完一句话后停顿片刻再继续模拟自然的说话节奏在播放一段动画、音效或过场效果期间保持对话挂起制造悬念或强调效果例如……之后停顿再揭示关键信息。与 commands.md 中列出的其他控制流命令jump、stop、visit、if不同wait不改变对话的执行路径只是在时间维度上暂停当前执行暂停结束后对话会从下一条语句继续。语法与参数约束wait的语法非常简洁它只接受一个参数且该参数必须是数值表达式// 等待 0.25 秒四分之一秒 wait 0.25 // 等待变量 $delay 指定的时长 wait $delay关于参数需要牢记以下三条约束参数必须是数值number既可以是数字字面量如0.25、2也可以是数值型变量如$delay。如果传入字符串等其他类型会在编译阶段直接报类型错误。秒数可以为 0wait 0是合法的相当于不暂停立即继续。秒数不能为负数负数的等待时长没有意义运行时会抛出DialogueError异常。完整的节点示例wait与其他内置命令一样只能在节点node内部使用而不能出现在.yarn文件根级根级目前仅允许declare与character两个编译期命令见 language.md。下面是一个在节点中使用wait的完整示例character Jenny title: pause_demo --- Jenny: 我先卖个关子…… wait 1.0 Jenny: 好了一秒钟过去了。 从源码看wait的实现原理理解了用法之后我们来看 wait_command.dart 中WaitCommand的完整实现这是整个命令的核心class WaitCommand extends Command { const WaitCommand(this.arg); final NumExpression arg; override String get name wait; override Futurevoid execute(DialogueRunner dialogue) { final seconds arg.value.toDouble(); if (seconds 0) { throw DialogueError(wait command with negative duration: $seconds); } return Future.delayed( Duration(microseconds: (seconds * 1000000).toInt()), ); } }从这段源码可以提炼出几个关键实现细节参数类型WaitCommand的构造参数是final NumExpression arg即该命令持有一个数值表达式NumExpression是 expression.dart 中定义的抽象类其value返回num类型。这正是必须传数值表达式这一约束在类型层面的体现。负数校验execute()首先将表达式求值结果转为double若小于 0 则抛出DialogueError(wait command with negative duration: ...)。注意这一校验发生在运行时因为只有当表达式真正求值后才能拿到具体数值。时间转换源码将秒转换为微秒精度seconds * 1000000取整后构造Duration。也就是说 Jenny 内部的等待精度可达微秒级0.25 秒会被精确转换为 250000 微秒。异步实现命令通过Future.delayed(...)返回一个延迟完成的Future这保证了wait是异步阻塞——它只会挂起当前对话节点的执行流而不会阻塞游戏主线程或 UI 渲染。Command基类与执行契约WaitCommand继承自抽象类Command见 command.dart其定义如下abstract class Command extends DialogueEntry { const Command(); FutureOrvoid execute(DialogueRunner dialogue); String get name; override Futurevoid processInDialogueRunner(DialogueRunner dialogueRunner) { return dialogueRunner.deliverCommand(this); } }每个命令都必须实现execute(DialogueRunner)与name。对wait而言name返回字符串wait。命令最终会通过DialogueRunner.deliverCommand()被投递给对话引擎执行。在DialogueRunner中的执行流程对话引擎 dialogue_runner.dart 中的deliverCommand()负责驱动所有命令的执行Futurevoid deliverCommand(Command command) async { await _combineFutures([ command.execute(this), if (command is UserDefinedCommand) for (final view in _dialogueViews) view.onCommand(command), ]); ... }这里有一个值得注意的差异wait是内置命令而非用户自定义命令因此引擎只需await command.execute(this)等待Future.delayed完成即可而UserDefinedCommand还会额外向所有注册的对话视图dialogue view派发onCommand/onCommandFinish事件参见 user_defined_commands.md。换句话说wait在引擎层面的行为是纯粹的时间延迟不会触发视图层的命令回调。典型应用场景与进阶用法1. 与本地变量结合动态控制时长wait.md 官方示例中展示了变量用法wait $delay。变量可以是全局变量通过declare声明或本地变量通过local声明详见 variables.md。利用这一点可以让同一段对话在不同上下文中使用不同的等待时长title: intro --- local $delay 0.5 我说出这句话之后停顿由 $delay 决定。 wait $delay 后面的内容会在 0.5 秒后出现。 变量的命名规则为以$开头后跟字母或下划线之后可以是字母、数字或下划线的任意组合如$delay、$_secret_并且变量类型在声明后不可改变。2. 参数可以是任意数值表达式由于wait的参数是NumExpression数值表达式它不限于字面量与变量也可以是运算符组成的算术表达式运算符详见 expressions.md// 等待 0.5 秒1.0 减 0.5 wait 1.0 - 0.5 // 基于变量计算等待时长 wait $base_delay * 2不过要注意Jenny 中的表达式总是同步求值的见 expressions.md因此wait的参数在求值时不会涉及异步操作或耗时的跨线程计算。3. 营造对话节奏与过场效果在游戏实践中wait常与行文本、if条件以及用户自定义命令如shakeCamera、fadeOut等见 user_defined_commands.md组合实现说一句、停一下、再继续的节奏控制title: suspense --- 守卫你确定要进去吗那个房间里……有点不对劲。 wait 1.5 守卫欲言又止 wait 0.75 守卫算了祝你好运。 解析与类型检查错误的写法如何被拦截wait的解析涉及词法分析tokenize与语法分析parse两个阶段相关实现位于 token.dart 与 parse.dart。在词法阶段wait会被识别为专门的Token.commandWait参见 token.dart 中的static const commandWait Token._(TokenType.commandWait);。在语法阶段parse.dart 中take(Token.commandWait)之后解析器会读取一个表达式并将其断言为数值类型最终构造出WaitCommand(expression as NumExpression)。测试用例 wait_command_test.dart 中的tokenize wait测试展示了wait 3被切分为如下 token 序列Token.startCommand Token.commandWait Token.startExpression Token.number(3) Token.endExpression Token.endCommand常见错误与排错指南根据源码与测试用例wait最常见的三类错误如下错误一参数类型不是数值wait two seconds编译期抛出类型错误TypeError: wait command expects a numeric argument at line 3 column 8: wait two seconds ^原因WaitCommand要求NumExpression而字符串字面量是StringExpression类型不匹配在编译阶段就被拦截对应测试wrong argument type。错误二语法错误——不允许多余参数wait 2 seconds解析期抛出语法错误SyntaxError: unexpected token at line 3 column 10: wait 2 seconds ^原因wait只接受一个数值参数2后面的seconds是多余的 token解析器无法识别对应测试wrong command syntax。错误三负数时长wait -1运行时抛出DialogueErrorwait command with negative duration: -1.0原因负数的等待时长没有意义wait_command.dart 中seconds 0时直接抛错对应测试negative duration。而wait 0是允许的因为0 0不成立Future.delayed(Duration.zero)会立即完成。测试验证等待时长如何被证明wait_command_test.dart 中的normal command wait测试是一个非常有意思的验证方式它在wait前后分别注册了startTimer与finishTimer两个自定义命令用毫秒时间戳差值来断言实际等待时长int getTime() DateTime.now().millisecondsSinceEpoch; // ... local $duration 1.0 before wait startTimer wait $duration finishTimer after wait // ... final elapsedTimeMs t1 - t0; expect(elapsedTimeMs, greaterThanOrEqualTo(1000));测试中$duration被设为 1.0 秒最终断言t1 - t0不小于 1000 毫秒。测试注释还提到本地测量约为 1015ms而在服务器测试流水线中由于环境原因可能高达 1400ms——也就是说wait保证的是至少等待指定时长实际耗时可能因调度与系统负载而略长这一点在依赖精确时序的场景中需要留意。小结wait是 Jenny 内置命令中最简单也最常用的时间控制工具语法为wait 数值表达式单位是秒0合法、负数非法参数必须是数值支持字面量、数值变量与算术表达式底层基于Future.delayed实现微秒级精度的异步暂停只挂起对话执行流不阻塞游戏主线程类型错误、多余参数、负数时长分别会在编译期或运行期被明确拦截。若想深入了解 Jenny 的完整命令体系if、jump、stop、visit等可继续阅读 commands.md变量与表达式细节见 variables.md 与 expressions.mdJenny 整体架构与.yarn文件格式见 jenny.md 与 language.md。【免费下载链接】flameA Flutter based game engine.项目地址: https://gitcode.com/GitHub_Trending/fl/flame创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

企业通讯软件怎么选?安全合规与高效协作兼得的选型指南

企业通讯软件怎么选?安全合规与高效协作兼得的选型指南

最近好几个朋友不约而同找我聊同一个话题:公司准备换企业通讯软件,到底怎么选。有人被厂商销售的话术绕晕了,有人觉得这只是“换一个聊天工具”的事,还有人直接把海外办公软件搬回来用,结果一轮合规审查就卡住了。这些…

📅 2026/9/16 3:52:08
服务器迁移后Let‘s Encrypt证书过期?自动续期机制排查与修复指南

服务器迁移后Let‘s Encrypt证书过期?自动续期机制排查与修复指南

你有没有遇到过这种情况:服务跑得好好的,突然某天早上收到一堆“网站打不开”“SSL证书错误”的告警。打开浏览器一看,整页的红色警告——证书过期。更气人的是,当初明明配置了 Lets Encrypt 证书自动续期,理论上它会自…

📅 2026/9/16 3:52:08
三角洲PC端自动下载怎么彻底关闭?启动器设置与系统后台禁用指南

三角洲PC端自动下载怎么彻底关闭?启动器设置与系统后台禁用指南

玩PC版三角洲(Delta Force)的朋友,估计早晚都会遇到这么一幕:晚上关机前看着硬盘还剩80G,第二天一开机,游戏启动器在后台吭哧吭哧下了大半天,一看游戏目录多了三四十个G,网络上传下载…

📅 2026/9/16 3:52:08
MORE NEWS

更多资讯

📰

打印沙漏题详解:从数学建模到代码实现的完整拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

RISC-V+ARM双芯协同实现嵌入式高精度人机交互

1. 项目概述:从芯片选型到人机交互的完整闭环FT900和R7KA8D2KFLCAC这两个型号,乍看像一串随机字符,但拆开来看——FT900是Fujitsu(富士通)推出的高性能32位RISC-V架构微控制器,主频高达200MHz,内…

📰

统信UOS共享打印机给Windows:配置、选型与报错排查全攻略

统信UOS共享打印机给Windows,这个需求最近问的人实在太多了。单位里办公电脑换了统信UOS,但旁边的Windows电脑还想用同一台打印机,网络里还混着各种笔记本、老台式机,打印机品牌从奔图到HP到兄弟都有。网上教程倒是不少&#xff0…

📰

Maya+V-Ray写实角色3S皮肤材质全流程:从节点连接到渲染设置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Boltzmann声学建模与C#送货单系统工程分离实践

简介:本资源是一份融合气动声学仿真与C#实战开发的双主题学习包,面向高校计算流体力学初学者及C#编程入门者,兼顾理论建模与工程实践。其中包含基于格子-玻尔兹曼方法(LBM)实现的不可压缩空腔流动气动声学模拟C语言源码…

📰

TypeScript泛型与类型安全实战:从基础操作符到infer高级用法

TypeScript 的泛型与类型安全,是这两年我面试前端岗位时几乎必问的一关,也是日常代码评审里最容易吵起来的话题。不少同学能把interface、type、联合类型这些基础概念背得滚瓜烂熟,但一遇到infer、条件类型、映射类型组合起来的高级写法就彻底…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬