跳转到内容

脚本图

脚本图是用节点和连线画出来、而不是敲出来的玩法逻辑。它是状态机与行为树 的可视化兄弟:图是一个 .esgraph 资产,由实体运行,它调用的叶子就是你在代码里注册一次的那些动作。 适合那种用状态机写起来别扭的短小、事件驱动的逻辑——游戏开始时生成这个;按下某键时按条件分支。

.esgraph 文件就是运行时定义:没有任何提前编译,编辑器里跑的图和包里发布的图是同一份字节。

  1. 在内容浏览器里 新建 → 新建脚本图。新资产会在文档标签里打开(双击任意 .esgraph 可重新打开)。
  2. 在画布上右键添加一个事件,再连出它要做的事。空图会直接提示这一点。
  3. 选中要运行它的实体,添加 ScriptGraphAgent 组件,把它的 graph 字段设为该资产。

资产按路径引用并随场景预加载,所以在代理第一次 tick 之前就已就绪。图在 Play(以及导出的游戏)中运行, 位于 Update 阶段,和状态机解释器并列。

连线 携带 方向
执行线(控制线) “接着运行” 推:事件点亮入口节点,沿线深度优先走下去。
数据线(数字、布尔、字符串、实体、任意) 一个值 拉:节点运行时,沿线向上求值来读取输入。

连线只在兼容的类型之间建立。没有连线的输入保存一个你在节点上填的常量。

顺序就是画面承诺的顺序:顺序节点先把第 0 个引脚的整条链走完,再开始第 1 个。 一个纯节点(没有执行引脚)同时喂给同一节点的两个引脚时,每次激活只求值一次,两个引脚看到同一个值; 下一次激活会重新求值,这正是循环条件能变成 false 的原因。

工具栏的节点按钮(或在画布上右键)按组列出节点(事件、流程、变量、常量、动作、取值、图):

分组 节点
事件 开始、每帧更新、销毁、监听事件(监听具名的实体事件)。每个都是入口,一张图可以有多个。
流程 分支、顺序(引脚数可配)、循环、延迟。
变量 读取变量、设置变量。
常量 数字、布尔、字符串字面量。
动作 带执行引脚、会做事的节点:timeline.play / timeline.pause、spriteAnim.play / restart / stop、audio.play / stop、soundEvent.trigger / stop、property.set、entity.despawn、debug.log、scene.load / reload、ui.setVisible、ui.setPage、fsm.fire、blackboard.set——以及你在代码里注册的所有动作。
取值 只产出值的节点(没有执行引脚):math.*(add、subtract、multiply、divide、min、max、abs、clamp、lerp、random)、compare.*(equal、less、greater)、logic.*(and、or、not)、string.concat、property.get、entity.self、entity.byName、input.down / pressed / axis / pointer——以及所有已注册的条件。
图 项目里其他可调用的图,用调用图节点来调用(在有图声明了入参之前为空)。

菜单按注册名列出这些动词;放到画布上之后,节点会用易读的标题(按名称找实体、按键按下、设置属性……),下面附上注册名。

你用 registerAction / registerCondition 注册的动作和条件——状态机、行为树用的是同一批——会按它们的声明带着对应端口出现在这里。 文件里只存动词的名字,所以旧图会按当前的声明重新绘制,不会保留动词早已没有的端口。

整理按依赖关系把节点从左到右排开;位置只用于编辑器,运行时忽略。

画布旁的面板有三个区——入参、出参和变量——各带数量和一个添加按钮,可搜索, 并显示每一项被读、被写的次数(或未使用)。

  • 变量区的添加声明一个带默认值的有类型变量。它由资产声明、按实体取值——两个运行同一张图的实体各自有自己的值。
  • 把变量拖到画布上:直接松手会询问读取还是设置;按住 Ctrl/⌘ 直接放读取节点,按住 Alt 直接放设置节点,不再询问。
  • 在变量那一行可以改名或更改类型。删除一个仍被节点使用的变量时会先确认;那些节点留在画布上,只是失去变量。

在入参区(输入引脚)或出参区(输出引脚)添加条目,这张图就变成可调用的。 别的图用调用图节点运行它,传值进去、读回结果——签名在被调用方身上,改了签名,所有调用方都会跟着重绘。

一次调用会在调用方的这一步里同步运行到结束。每个调用点为被调用图保留自己的帧,被调用图消耗的是调用方的步数预算, 嵌套深度也有上限——经过环路再次到达自己的图会停下来,而不是把栈撑爆。

每次节点激活消耗一步,一个实例每个 tick 有步数预算(默认 4096)。一张无限循环的图——一个永远不会变 false 的循环—— 会停下来、指出耗尽预算的那个节点,并保持停止,而不是把编辑器卡死。调用最多嵌套 16 层。 引用了不存在的图、预制体或动词,只会报告一次,不会每帧刷屏。

图也可以不通过资产直接注册:

import { registerScriptGraph, ScriptGraphAgent } from 'esengine/logic';
registerScriptGraph('door-open', graphData); // 一个 ScriptGraph 对象
cmds.spawn().insert(ScriptGraphAgent, { graph: 'door-open' });

ScriptGraphAgent.graph 既可以填注册名,也可以填 .esgraph 路径。动作所在的注册表见 AI → 在编辑器里编排。