Verse Wiki — 写给蓝图作者的 Verse 手册
技巧 · EXTRA

把节点图「读」成代码的四步法

主课给了五条规则,那是「看到代码怎么想」。这一页给的是反方向的操作流程:手边有一张你自己搭的节点图,怎么在四步之内把它变成代码。这套流程不需要你记住任何 Verse 语法——它只要求你会读自己的图。

一、四步总览

先把流程摆出来。每一步只做一件事,做完再做下一步,不要跳:

  1. 找起点——在图上找到那个红色的事件节点。它是整条执行线的车头,也是你代码的第一行。
  2. 顺着白线抄成行——从车头沿着白色执行线一路往右,每经过一个节点,就在下面加一行。
  3. 数据线塞进括号——每个节点身上那些彩色输入引脚上挂的东西,原样写进这一行的圆括号里。
  4. 分支画成缩进——遇到 Branch、ForEach 这种「岔口」,把从岔口出去的那一段,整体往右缩一格。

四步做完,你手上就是一段结构正确的代码骨架。剩下的只是查一下每个节点在 Verse 里叫什么名字——那是查表的活,不是理解的活。

二、第一步:找到执行线的起点

一张事件图表上可能有好几条互不相干的执行线(BeginPlay 一条、某个按钮的事件一条、Tick 一条)。一次只翻译一条。先用眼睛把这一条从头捋到尾,确认它的车头是谁。

车头决定你代码的第一行长什么样。常见的三种:

图上的车头 代码里的第一行
Event BeginPlay OnBegin<override>()<suspends>:void =
某个设备/Actor 上的事件(按钮被按、触发盒被踩) 一个你自己起名的函数,再在 OnBegin 里把它订阅到那个事件上
自定义事件(Custom Event)/ 自定义函数 一个你自己起名的函数,由别的地方调用它

第二种最常见,也最容易卡住新手,值得多说一句。蓝图里你会把一个事件拖到图上,它就自动挂好了;Verse 里没有画布可拖,所以要用一行代码明说「把这个函数挂到那个事件上」,这行代码通常写在 OnBegin 里。这跟你在蓝图里用 Bind Event to … 把一个自定义事件绑到 Event Dispatcher 上是同一回事——只不过在 Verse 里,所有事件都走这条路。

三、第二步:顺着白线,抄成从上到下的行

从车头出发,沿白色执行线走。每经过一个节点,往下写一行;白线走到哪,行就写到哪。这一步几乎不需要思考,它就是把「从左到右」旋转成「从上到下」。

三个提醒:

四、第三步:数据线上的东西,写进括号

现在给每一行填料。看这个节点的输入引脚上挂着什么,按引脚从上到下的顺序,写进这一行的圆括号里,逗号隔开。

顺手说一个蓝图有、代码没有的能力:图上你可以把一根数据线拉给好几个节点共用。代码里做不到「一根线分叉」,对应的写法是先把值存进一个名字,再在几个地方引用这个名字——也就是多写一行。这是本页唯一一处「翻译后行数会变多」的地方。

五、第四步:分支画成缩进

白线遇到 Branch 就分叉:True 一条、False 一条。代码里没有分叉,只有缩进——从岔口出去的那一整段,往右缩一格,写在判断那一行的下面。

翻译口诀:「判断那一行原地不动,从它引出去的那一段整体往右缩一格」。ForEach 也一样:循环体是从循环节点引出去的一段,所以整体缩进;循环结束后继续的那部分,回到原来的那一列。

这一步是四步里唯一需要动脑的:你得看清楚,图上那条线到底是「从岔口出去的」还是「岔口之后汇合回来的主干」。汇合回主干的那部分不缩进,和判断那一行对齐。看不清的时候有个笨办法很管用:用手指顺着白线走一遍,每进入一个分支就在心里往右挪一格,每退出来就挪回去。

六、动手练一遍:一次性金库按钮

拿一张真图走一遍完整流程。机制是:金库旁边有个按钮,按一下开门,但只能用一次。你在蓝图里大概会这么搭:

图上的东西 细节
变量面板 Button(按钮引用)、Vault(门引用)、Charges(整数,默认 1)
车头 按钮的「被交互」事件——在蓝图里你会用 Bind Event 把它绑到一个自定义事件上
节点 1 Branch:条件引脚上接着 Charges > 0
节点 2(True 分支) Set Charges,值是 Charges - 1
节点 3(True 分支) 调用门上的 Open
False 分支 什么都不接

四步走:① 车头是设备上的事件,所以要写一个自己起名的函数 OnPressed,再在 OnBegin 里把它订阅上去。② 顺着 True 分支的白线,两个节点抄成两行。③ 数据线:Charges - 1 是纯节点的计算,写进赋值那一行;Open 是从 Vault 上拖出来的,写成 Vault.Open()。④ Branch 的 True 分支整体往右缩一格。结果:

vault_device.verse
using { /Fortnite.com/Devices }

vault_device := class(creative_device):

    @editable Button:button_device = button_device{}
    @editable Vault:door_device = door_device{}

    # 变量面板里的整数变量,默认 1
    var Charges:int = 1

    OnBegin<override>()<suspends>:void =
        # 第一步:把 OnPressed 挂到按钮的事件上(相当于 Bind Event)
        Button.InteractedWithEvent.Subscribe(OnPressed)

    # 这个函数就是那个「自定义事件」
    OnPressed(Agent:agent):void =
        # 第四步:Branch 的 True 分支整体往右缩一格
        if (Charges > 0):
            set Charges -= 1
            Vault.Open()

对照一下:图上那个 Branch 变成了 if 那一行;True 分支的两个节点变成了缩进的两行;False 分支什么都不接,所以代码里干脆没有对应的东西——这是代码比图省事的地方之一:空分支不用画。而 set 就是那个 Set 节点,主课的规则 ② 提过它,第 8 课会正式讲。

最后提醒一句常见的翻车点:这里用的是 Subscribe(订阅),不是主课那段代码里的 Await(等待)。区别很实在——Await 是「执行线停在这里,等一次就往下走」,适合一次性的流程;Subscribe 是「挂上去,以后每次都响应」,适合按钮这种要反复触发的。图上分别对应「等待型 latent 节点」和「Bind Event 到自定义事件」。选错了,表现就是「只灵了一次」或者「多绑了好几遍」。第 25 课专门算这笔账。

七、小测验

按四步法翻译,蓝图 Branch 节点的 True 分支在代码里变成了什么?