事件
启动 event 图的事件 Head、它们各自携带的 payload,以及在蓝图之间传递消息的 Broadcast 节点
事件 Head 是一张event图的起点。它没有执行入口——运行时从 Head 进入这张图,执行链从then开始。本页其余内容都由这一点展开:Head 的数据输出就是这次事件的 payload,而你能用到哪些 Head,取决于蓝图挂在什么宿主上
约定
- Head 没有执行入口。 没有任何东西可以连进去。一张图里可以放多个 Head,各自的事件到达时各跑各的执行链
- 数据输出就是 payload。 除
then以外的每个输出引脚,都按引脚 id 读取本次运行时事件 payload 的一个字段。派发没有设置的字段读到null——不是0,也不是"" - 坐标是设计坐标。 元素的鼠标 Head 使用该元素自己的本地设计坐标系;放在 Surface 蓝图上的
Mouse Click和Right Click则使用该 Surface 的设计坐标系 - 图类型。 本页节点都只允许
event图,只有Send Broadcast和Get Listener Count同时允许macro图。Blueprint Value 图只接受两个 Head:Init和On Flush - 不可交互的元素不派发。 控件处于禁用或文本编辑等不可交互状态时,完全不派发它的交互 Head
哪些 Head 可用
创建浮窗按蓝图 owner 过滤 Head。没有为你的 owner 列出的 Head,不是被某个开关藏起来了——在那里它根本不存在
| 宿主 | 提供的 Head |
|---|---|
全局蓝图(globalMain) | App Boot、On Game Ready、On Fullscreen Changed、On Window Close Requested、On Action、四个键盘 Head、两个 preference Head |
Surface 蓝图(surfaceMain) | Surface Init、Surface Unmount、Before Surface Exit、After Surface Enter、Mouse Click、Right Click、On Fullscreen Changed、On Window Close Requested、On Action、四个键盘 Head、两个 preference Head、两个 broadcast Head、Element Flush、Element Click |
控件私有蓝图(widgetMain、componentWidgetMain) | 由该控件类型声明的能力决定,见下表 |
Blueprint Value(widgetValue) | Init与On Flush |
| Story Action 蓝图 | On Call |
对控件来说,owner 只是规则的一半:每种内建控件都声明了一组事件能力,只有该控件自己列出的 Head 才会出现。这就是为什么nl.list没有Mouse Enter,而nl.container没有Item Click
| 控件类型 | Head |
|---|---|
| 所有支持私有蓝图的控件 | Init、On Flush、Unmount、Before Surface Exit、After Surface Enter、四个键盘 Head、On Fullscreen Changed、On Broadcast、On Any Broadcast、Element Flush、Element Click |
nl.container、nl.text、nl.image、nl.button、nl.dialog.sentence、nl.nvl.texts | 九个鼠标 Head、Focus、Blur、List Item Refresh |
nl.video、nl.puppet | 九个鼠标 Head、Focus、Blur |
nl.switch | 九个鼠标 Head、Focus、Blur、Changed、Turned On、Turned Off |
nl.list、nl.notification.list、nl.choice.list、nl.nvl.list | Scroll、Scroll End、Item Render、Item Click、Item Hover、Selection Changed |
nl.slider | Drag Start、Value Changed、Drag End |
nl.textInput | Value Changed、Submit、Focus、Blur |
nl.frame | Page Event |
控件蓝图内部还有两层收窄。List Item Refresh只有当元素确实位于 List 的 item 模板之内时才提供。另外,创建时绑定了某个事件的事件图层只提供该事件的 Head;创建时 Event 字段保持-的图层没有绑定,提供该控件类型允许的全部 Head
事件冒泡
元素事件只在运行时命中的那个元素上触发,然后就停在那里——它不会向上传给祖先,父元素也不会默默接管子元素的事件。Element 分类里的两个节点负责改变这一点:
曾经用来控制它的两个节点 Continue Event Bubble 与 Stop Event Bubble 已经被删除。它们真正被稳定用到的那一件事 —— 把窗口关闭挂住 —— 现在是 App 分类下的 Keep Window Open,它只做这一件事
焦点位于文本输入元素时,窗口级键盘派发被整体跳过:全局与 Surface 的On Key Down/Any Key Down都不会执行,所以输入名字时按 Space 不会推进对话、按 Escape 不会打开菜单。获得焦点的控件自己的键盘 Head 仍然照常触发——它们走的是 DOM 冒泡,不是窗口监听
应用生命周期
全局蓝图的入口,外加两个同样能到达 Surface 和控件的窗口事件
App Boot
blueprint.event.head.appBoot
App Boot(应用启动)在 UI 运行时完成启动、并拥有可执行的全局蓝图时触发一次
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
On Game Ready
blueprint.event.head.gameReady
On Game Ready(游戏就绪时)在每个被接受的 NarraLeaf session 触发一次:此时LiveGame对象已创建并存入 Studio runtime,但liveGame.newGame()还没有启动第一段剧情
运行时把 NarraLeaf 环境初始化当作一个加载项,放在 Surface 系统启动之前:它以 Story 库默认 Story 的入口场景的 compiled story 挂载 Player,因此LiveGame已经存在、该场景资源开始预热,而玩家仍停留在主菜单。真正「进入游戏」只发生在Start Game或读档时,并且复用同一个已初始化的LiveGame:当Start Game的目标就是已预热的默认场景时为秒开,不会再次触发该 Head;只有Start Game指向不同场景时才会重新挂载环境并第二次触发。项目未配置默认 Story 时改为挂载一个空环境,该 Head 在启动时依然触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
把 NarraLeaf Preference 的初始化放在这里——Set Auto Forward、Set Game Speed、Set Voice Volume、Set Sentence Speed——这样它们在玩家进入游戏之前就已就绪。不要放在App Boot里:名字虽然像最早的钩子,它并不最先执行(On Game Ready先于它触发),而且它不保证此刻存在活动的 live game
On Fullscreen Changed
blueprint.event.head.fullscreenChanged
On Fullscreen Changed(全屏状态变更时)在应用窗口进入或退出全屏时触发,包括在游戏之外切换全屏的情况。它是环境型窗口事件,因此派发是扇出的:先全局蓝图,再当前 active Surface 蓝图,最后该 Surface 上所有声明了该 Head 的控件蓝图。所以设置面板里的控件不必拥有整个 Page 也能跟随窗口状态
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
isFullscreen | out · data | boolean | 变化后的状态 |
On Window Close Requested
blueprint.event.head.windowCloseRequested
On Window Close Requested(窗口关闭请求时)在玩家请求关闭窗口时触发。主进程会把这次关闭挂起,等全局蓝图、再等 Surface 蓝图跑完;两者中任意一个执行了 Keep Window Open 就取消关闭,没有则窗口继续关闭。在 Studio Dev Mode 中它覆盖 Dev Mode 窗口,在预览和正式产物中覆盖游戏窗口
只在全局蓝图和 Surface 蓝图中提供。取消动作依附于本次派发共享的 event control,而控件派发路径不传递它——这和键盘 Head 止步于 Surface 是同一个原因
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
Surface 生命周期与进退场
Surface Init和Surface Unmount属于 Surface 蓝图。两个进退场 Head 也可用于元素私有蓝图,但只有该元素在那一刻已挂载且仍存活时才会收到
Surface Init
blueprint.event.head.surfaceInit
Surface Init(画面初始化)在 Page 或游戏界面 Surface 首次进入当前运行时 scope 时触发。顶层 Surface 用自身 id 作为 scope;由 Page 组件嵌入的子 Page 拥有独立的runtimeScopeId,因此同一个 Page 被两个 Page 组件引用时彼此隔离
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
Surface Unmount
blueprint.event.head.surfaceUnmount
Surface Unmount(画面卸载)在 Page 或游戏界面 Surface 离开当前运行时 scope、被替换,或其宿主 Page 组件实例卸载时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
Before Surface Exit
blueprint.event.head.beforeSurfaceExit
Before Surface Exit(画面退出前)在当前 Page——或嵌入的子 Page——即将开始退出动画时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
After Surface Enter
blueprint.event.head.afterSurfaceEnter
After Surface Enter(画面进入后)在当前 Page 完成进入动画后触发。没有动画或处于 reduced motion 时,它在预绘制完成、Surface 进入稳定显示状态后触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
元素生命周期
Init
blueprint.event.head.init
Init(初始化)在支持私有蓝图的元素完成首次渲染并挂载后触发一次。它不是渲染前的 hook。Dev Mode bundle revision 导致 Surface 或元素 remount 时会再次触发。在 Blueprint Value 中它是初始求值入口;后续求值来自隐藏的 Element 属性依赖,或来自显式的On Flush
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
Unmount
blueprint.event.head.unmount
Unmount(卸载)在元素从运行时元素树中移除时触发:Surface 关闭或被替换、Frame 切换子 Page、List item 实例被移除,或可见性导致元素完全不渲染。运行时display: none只是隐藏并保持挂载,不会触发它
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
On Flush
blueprint.event.head.flush
On Flush(刷新时)在当前蓝图所属元素被蓝图 Host API 显式改写属性、并因此触发重绘时执行。渲染器自动计算的 CSS 状态样式(hover、focus 变体)不会触发它。在 Blueprint Value 中它兼作显式求值入口:默认 Dialog Nametag 就是靠这个入口在 Dialog 不重新挂载的情况下随对话推进刷新
Flush 是属性提交后的批处理通知。运行时按帧合并同一元素的 flush;flush 处理器内部再次改写该元素时,新的 flush 进入下一帧的批次——不存在同步重入
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
element | out · data | element | 被刷新的元素引用 |
鼠标
这些 Head 可用于 displayable 控件。Mouse Click和Right Click额外可用于 Surface 蓝图,此时表示「当前 Surface 内任意位置」。Surface 进退场期间,鼠标与点击类事件会等到 Surface interaction ready 后才派发
Mouse Click
blueprint.event.head.mouseClick
Mouse Click(鼠标点击)在元素上完成一次点击时触发。用于 Surface 蓝图时表示当前 Surface 内任意点击,并输出 Surface 设计坐标
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Double Click
blueprint.event.head.mouseDoubleClick
Mouse Double Click(鼠标双击)在元素上完成一次双击时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Down
blueprint.event.head.mouseDown
Mouse Down(鼠标按下)在元素上按下鼠标按键时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float | |
button | out · data | integer | 鼠标按键编号 |
Mouse Up
blueprint.event.head.mouseUp
Mouse Up(鼠标抬起)在元素上松开鼠标按键时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float | |
button | out · data | integer | 鼠标按键编号 |
Mouse Enter
blueprint.event.head.mouseEnter
Mouse Enter(鼠标进入)在指针进入元素区域时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Leave
blueprint.event.head.mouseLeave
Mouse Leave(鼠标离开)在指针离开元素区域时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Move
blueprint.event.head.mouseMove
Mouse Move(鼠标移动)在指针于元素上移动时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
Mouse Wheel
blueprint.event.head.mouseWheel
Mouse Wheel(鼠标滚轮)在滚轮于元素上滚动时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float | |
deltaX | out · data | float | 横向滚动量 |
deltaY | out · data | float | 纵向滚动量 |
Right Click
blueprint.event.head.rightClick
Right Click(右键点击)在元素触发上下文菜单事件时触发。用于 Surface 蓝图时表示当前 Surface 内任意右键点击,输出 Surface 设计坐标。事件成功派发时,默认上下文菜单会被阻止
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
x | out · data | float | |
y | out · data | float |
焦点
Focus
blueprint.event.head.focus
Focus(聚焦)在元素获得键盘、鼠标或手柄焦点时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
Blur
blueprint.event.head.blur
Blur(失焦)在元素失去焦点时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
键盘
键盘事件由运行时窗口级监听派发,不依赖元素焦点。全局蓝图、当前 active Surface 蓝图,以及所有已挂载且拥有该 Head 的控件,都会收到同一次窗口事件,并各自执行自己的链。控件的键盘监听随控件挂载注册,卸载时自动移除
Surface 完成 prepaint 之后,Page 进退场期间键盘事件仍会派发。需要在过渡期间屏蔽时,在图里用 Page 分类的Is Surface Entering、Is Surface Exiting或Is Surface Transitioning分支
只想匹配一个绑定时用带过滤的一对,想拿到按键本身时用Any Key一对:On Key Down/On Key Up匹配卡片上配置的绑定且不携带 payload,而Any Key Down/Any Key Up对每个按键都触发,并给出key和各修饰键状态
On Key Down
blueprint.event.head.keyDown
On Key Down(按键按下时)在运行时窗口收到匹配的键盘按下事件时触发。不要求任何元素处于焦点状态
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
卡片字段
| 字段 | 说明 |
|---|---|
Key | 键盘绑定。卡片显示当前绑定;点击后在按钮上方打开捕获浮窗,按下任意按键即可绑定,支持Ctrl/Alt/Shift/Meta组合键。单键绑定按KeyboardEvent.key大小写不敏感匹配;绑定中包含修饰键时,修饰键状态也必须匹配。空值永远不触发——任意键请用Any Key Down |
On Key Up
blueprint.event.head.keyUp
On Key Up(按键抬起时)在运行时窗口收到匹配的键盘抬起事件时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
卡片字段
| 字段 | 说明 |
|---|---|
Key | 与On Key Down相同的绑定控件。空值永远不触发——任意键请用Any Key Up |
Any Key Down
blueprint.event.head.anyKeyDown
Any Key Down(任意按键按下)在运行时窗口收到任意键盘按下事件时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
key | out · data | string | 按键语义值,对应KeyboardEvent.key |
altKey | out · data | boolean | |
ctrlKey | out · data | boolean | |
shiftKey | out · data | boolean | |
metaKey | out · data | boolean | Meta / Command / Windows |
Any Key Up
blueprint.event.head.anyKeyUp
Any Key Up(任意按键抬起)在运行时窗口收到任意键盘抬起事件时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
key | out · data | string | 按键语义值,对应KeyboardEvent.key |
altKey | out · data | boolean | |
ctrlKey | out · data | boolean | |
shiftKey | out · data | boolean | |
metaKey | out · data | boolean | Meta / Command / Windows |
输入动作
On Action
blueprint.event.head.action
卡片上选中的那个输入动作被触发时触发,不论玩家是怎么触发的。
动作是工程给某个手势起的名字——“推进”“打开记录”“取消”——而它背后的绑定写在工程的动作词表上、以及每个 Surface 对它的回应里,从来不写在图上。这正是这个 Head 存在的意义:作者按名字选动作,至于哪个键、哪次点击算数,那是工程的事。卡片存的是动作的 id,所以给动作改名不会让任何图失去指向。
只能用于全局与 Surface 图。一个动作按其构造就是整块面板范围的,所以它属于那两个能代表整块面板的宿主:Surface 回答它启用了哪些动作,全局蓝图回答那些在每一页上含义都相同的手势。一个控件说“在我这里点一下就是推进”,正是词表要取代的那种安排——想要原始手势的元素仍然有它自己的鼠标 Head。
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
source | out · data | string | 是哪一类输入触发的:pointer、key、gamepad 或 touch |
x | out · data | float | 手势落点,与鼠标 Head 用的是同一套坐标 |
y | out · data | float |
卡片字段
| 字段 | 说明 |
|---|---|
Action | 工程的输入动作之一 |
对按键和手柄绑定来说 x / y 没有意义,在那里读作 0——这正是 source 紧挨着它们的原因:它就是那个说明另外两个有没有意义的引脚。同一个动作确实会因来源不同而想要不同的行为:来自一次点击的“推进”有一个屏幕上的位置可以回应,来自空格键的没有。
要问某个动作是否正被按住而不是对它被触发做出反应,用 Input 里的 Is Action Held。
绑定元素的 Head
这两个 Head 先绑定同一 Surface 内的目标控件——和Element节点一样——然后监听那个控件而不是自己。它们同时也是元素绑定来源:Element 派生节点只有在当前图里已经存在兼容的Element、Element Flush或Element Click时才出现在创建浮窗中,而它们的element输出可以直接连到这类节点的目标输入
Element Flush
blueprint.event.head.elementFlush
Element Flush(元素刷新)监听绑定目标的 flush。目标控件被 Host API 显式改写属性并重绘后,当前蓝图中的该 Head 执行
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
element | out · data | element | 被刷新的绑定元素引用 |
Element Click
blueprint.event.head.elementClick
Element Click(元素点击)监听绑定目标自己的mouseClick。目标控件收到真实点击后该 Head 执行;它不依赖点击穿透,也不依赖父子冒泡。默认 Dialog 模板用它把推进逻辑集中在一处:Dialog Content 蓝图自己用Mouse Click,同时用Element Click绑定全屏透明的 Dialog Interaction Layer、可见的 Dialog Panel 和默认内容子控件,全部连到同一个 Game Next
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
element | out · data | element | 被点击的绑定元素引用 |
x | out · data | float | 使用目标元素的本地设计坐标 |
y | out · data | float | 使用目标元素的本地设计坐标 |
button | out · data | integer | 鼠标按键编号 |
List
这些 Head 属于 list-like 控件——nl.list以及游戏界面包装控件nl.notification.list、nl.choice.list、nl.nvl.list。读写运行时内容见 List 节点。List Item Refresh是个例外:它派发到 item 模板内部元素的私有蓝图,而不是 List 本身
Item Render
blueprint.event.head.itemRender
Item Render(项渲染)在 List 根据绑定数据、预览数据或预览数量渲染单个条目实例时触发。payload 来自该条目的 scope
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
index | out · data | integer | |
count | out · data | integer | 本次渲染的条目总数 |
key | out · data | string | 优先来自 List 的itemKeyPath |
item | out · data | json | 条目数据 |
Item Click
blueprint.event.head.itemClick
Item Click(项点击)在条目容器收到点击时触发。点击条目模板内的子元素也会归属到对应条目
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
index | out · data | integer | |
count | out · data | integer | 本次渲染的条目总数 |
key | out · data | string | 优先来自 List 的itemKeyPath |
item | out · data | json | 条目数据 |
Item Hover
blueprint.event.head.itemHover
Item Hover(项悬停)在指针进入条目容器时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
index | out · data | integer | |
count | out · data | integer | 本次渲染的条目总数 |
key | out · data | string | 优先来自 List 的itemKeyPath |
item | out · data | json | 条目数据 |
Selection Changed
blueprint.event.head.selectionChanged
Selection Changed(选择变更)在条目点击导致运行时选中索引变化时触发。List 以selectedIndex属性作为初始选中值;同一运行时实例内重复点击当前选中条目不会再次触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
index | out · data | integer | 新选中的条目 |
previousIndex | out · data | integer | 之前没有选中项时为-1 |
count | out · data | integer | 本次渲染的条目总数 |
key | out · data | string | 新选中条目的 key |
item | out · data | json | 新选中条目的数据 |
Scroll
blueprint.event.head.scroll
Scroll(滚动)在 List 的滚动容器发生滚动时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
offset | out · data | float | 当前滚动位置 |
maxOffset | out · data | float | 最大滚动位置 |
progress | out · data | float | 通常为0到1 |
Scroll End
blueprint.event.head.scrollEnd
Scroll End(滚动结束)在滚动容器从非末端滚动到末端时触发。已经停留在末端时,后续相同滚动事件不会重复触发;离开末端后再次到达末端会重新触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
offset | out · data | float | 当前滚动位置 |
maxOffset | out · data | float | 最大滚动位置 |
progress | out · data | float | 通常为0到1 |
List Item Refresh
blueprint.event.head.listItemRefresh
List Item Refresh(列表项刷新)在nl.list渲染或刷新某个条目时,派发到该条目 item 模板后代元素的私有蓝图。模板子元素靠它读取当前条目的数据。每个重复条目实例使用独立的 instance key 和 item scope,因此 element id 相同的两个条目不会共享 locals
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
props | out · data | json | item是 object 时为item本身,否则为{ value: item } |
item | out · data | json | 条目数据 |
index | out · data | integer | |
count | out · data | integer | 本次渲染的条目总数 |
key | out · data | string |
Slider
这些 Head 属于nl.slider。这里的所有值都是映射后的值,和props.value以及 Slider 节点一致——0–1 normalized 值只能通过专用读节点取得
Drag Start
blueprint.event.head.sliderDragStart
Drag Start(拖拽开始)在滑块拖拽开始时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
value | out · data | float | 映射值 |
Value Changed
blueprint.event.head.sliderValueChanged
Value Changed(值变更)在运行时值发生变化时触发。派发按动画帧合并,并且在一条链还在执行时,后续变化会塌缩成一次待发派发——所以拖动不会每像素触发一次,previousValue覆盖被合并掉的全部变化。用Set Slider Value写入值不会派发该 Head
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
value | out · data | float | 映射值 |
previousValue | out · data | float | 映射值 |
Drag End
blueprint.event.head.sliderDragEnd
Drag End(拖拽结束)在滑块拖拽结束时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
value | out · data | float | 映射值 |
Switch
nl.switch 上的三个 Head,讲的都是玩家自己去拨它。从图里写状态——Switch 里的 Set Checked、Turn On、Turn Off、Toggle——不会派发其中任何一个,因此一张既写又听同一个开关的图不会把自己触发起来。
一次拨动先触发 Changed,然后触发 Turned On / Turned Off 之中恰好一个,顺序如此,且后一个要等前一条链跑完。拨到它本来就在的那个状态则什么也不触发。
Changed
blueprint.event.head.switchChanged
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
checked | out · data | boolean | 新状态 |
previousChecked | out · data | boolean |
Turned On
blueprint.event.head.switchTurnedOn
Changed 中不需要分支的那一半——给只在一个方向上有事可做的处理用。
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
Turned Off
blueprint.event.head.switchTurnedOff
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |
文本输入
这些 Head 属于nl.textInput。读写字段内容见 Text input 节点
Value Changed
blueprint.event.head.textInputValueChanged
Value Changed 在输入框的值发生变化时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
value | out · data | string | |
previousValue | out · data | string |
Submit
blueprint.event.head.textInputSubmit
Submit(提交)在输入框内按下Enter时触发。它刻意不阻止事件传播,因此同一个输入框上绑定了Enter的控件On Key Down会与Submit一起继续触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
value | out · data | string | 提交时的值 |
Page
Page Event
blueprint.event.head.pageEvent
Page Event(页面事件)在嵌入某个 Page 组件的子 Page 调用Emit Page Event时,于父级nl.frame的私有蓝图中触发。只有nl.frame提供该 Head;发送侧位于 App 节点
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
event | out · data | string | 子 Page 发出的事件名 |
data | out · data | json | 子 Page 发出的事件数据 |
Game Preference
两个 Head 都订阅当前活动LiveGame的 preference 派发器,因此只在全局蓝图和当前 active Surface 蓝图中提供。没有活动 game runtime 时不会订阅,也不会触发;On Game Ready之后运行时在新的LiveGame上重新订阅。Preference Setter(如Set BGM Volume)和 NarraLeaf 内部写入都会触发它们,并且写入相同值不保证被去重——所以不要在监听某个偏好的图里再写入同一个偏好,那会构成自触发循环。Getter 和 Setter 见 Game 节点
On Preference Changed
blueprint.event.head.preferenceChanged
On Preference Changed(偏好变更时)在所选偏好键变化时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
value | out · data | json | 变化后的新值。引脚类型是通用json;实际运行时类型由所选键决定——autoForward/skip/showDialog为boolean,voiceEndMode为string,其余为number。接入Set Slider Value这类强类型输入前,先用To Float或To Boolean转换 |
previousValue | out · data | json | 运行时缓存的旧值,类型同value。本次会话对该键没有更早快照时为null |
卡片字段
| 字段 | 说明 |
|---|---|
Preference | 要监听的偏好键,共十六个:autoForward、autoForwardDelay、skip、skipping、skipReadText、showDialog、gameSpeed、cps、voiceVolume、voiceFadeDuration、voiceEndMode、bgmVolume、soundVolume、globalVolume、skipDelay、skipInterval。空值不订阅任何键——任意键请用On Any Preference Changed |
On Any Preference Changed
blueprint.event.head.anyPreferenceChanged
On Any Preference Changed(任意偏好变更时)在任意偏好键变化时触发。用于集中处理设置变更——统一持久化当前设置,或一次性刷新整个设置面板
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
key | out · data | string | 发生变化的规范键名,例如bgmVolume |
value | out · data | json | 变化后的新值;实际类型由key决定 |
previousValue | out · data | json | 类型同value;没有更早快照时为null |
Broadcast
Broadcast 在当前 active Surface 的各蓝图之间传递具名消息:该 Surface 自己的蓝图,加上它上面的所有控件蓝图。它不会到达全局蓝图,也不跨 Surface;发送者自己如果也在监听,同样会收到自己发出的广播。目标来自文档而不是已挂载的 React 树。四个节点都只在 Surface 蓝图和控件蓝图中提供
On Broadcast
blueprint.event.head.onBroadcast
On Broadcast(广播时)在收到指定名称的广播时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
data | out · data | json | 广播数据 |
sender | out · data | string | 发送方元素 ID;没有发送者时为空字符串 |
卡片字段
| 字段 | 说明 |
|---|---|
Event | 要监听的广播事件名。去除首尾空白后精确匹配 |
On Any Broadcast
blueprint.event.head.onAnyBroadcast
On Any Broadcast(任意广播时)在本蓝图收到任意名称的广播时触发
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — | |
event | out · data | string | 广播事件名 |
data | out · data | json | 广播数据 |
sender | out · data | string | 发送方元素 ID;没有发送者时为空字符串 |
Send Broadcast
blueprint.broadcast.send · Latent
Send Broadcast(发送广播)向运行中的 UI 发送一个广播事件,等所有监听链跑完后从next继续。事件名为空或只有空白是执行错误,不是静默 no-op。发送者 id 由正在执行的蓝图所属元素填入
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
in | in · exec | — | |
next | out · exec | — | |
event | in · data | string | 可在卡片上直接填字面量 |
data | in · data | json |
Get Listener Count
blueprint.broadcast.getListenerCount · Pure
Get Listener Count(获取监听器数量)读取当前 Surface 上某个广播事件名已注册的监听器数量
统计的是 Head 而不是蓝图:一张图里有两个匹配 Head 就计两次,一个On Any Broadcast对每个事件名都计数。Head 从文档中统计,因此当前未挂载的元素同样计入
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
event | in · data | string | 可在卡片上直接填字面量 |
count | out · data | integer |
Story Action
On Call
blueprint.event.head.onCall
On Call(被调用时)是 Story Action Blueprint——与某个剧情动作一一绑定的蓝图——的唯一入口,在其他任何地方都不提供。Story Action 图会被编译成 NarraLeaf 的Script动作并经剧情编译器执行,永远不走 UI 事件派发路径,因此本页其余 Head 在该 owner 中都不出现
| 引脚 | 方向 | 类型 | 说明 |
|---|---|---|---|
then | out · exec | — |