Files
ichni_Creator_Studio/Assets/Scripts/Editor Tools/NodeScript/总览.md
2026-05-23 21:05:16 +08:00

9.9 KiB
Raw Blame History

NodeScript 系统总览

文件结构

Editor Tools/NodeScript/
├── NodeCore.cs                  # 核心类型:生命周期、连接器、动态类型
├── NodeManager.cs               # 调度中心 + UI 交互
├── NodeObject.cs                # MonoBehaviour节点 UI、插槽、选中、状态显示
├── ConnectorSlot.cs             # 连接点交互 + 外观刷新
├── NodeUIBuilder.cs             # UI 构建Dropdown / FloatField / Toggle / TypeDropdown
├── NodeCompoments/
│   ├── NodeCompoment.cs         # 操作 / 控制流节点
│   └── NodeUtility.cs           # 工具 / 常量 / 变量节点
├── Node重构.txt                  # 重构需求文档
├── Node重构大纲.md               # 详细重构设计
└── 总览.md                      # 本文件

一、执行模型:拉取式 + 生命周期

1.1 周期调度

RunGraph():
  1. ComputeLValues()         — BFS 算所有节点到 Start 的最短距离 L
  2. triggerTable = {全部节点}
  3. while triggerTable  runtimeTable 非空:
       RunCycle()

RunCycle():
  1. triggerTable 并入 runtimeTable清空 triggerTable
  2. foreach node in runtimeTable:
       result = node.Loop()
       收集 triggers → triggerTable
       if TriggerDownstream → 自动发现下游节点 → triggerTable
       if RemoveFromRuntime → 标记移除
  3. runtimeTable -= 已完成的节点

1.2 节点状态

状态 含义
Ready 等待本周期执行
Hang 前置节点未完成,挂起到下一周期
Complete 已完成,移出 runtimeTable

1.3 LoopResult 返回类型

工厂方法 RemoveFromRuntime TriggerDownstream 用途
Complete() true true 节点完成,触发下游
Hang(preceding) false false 等待前置节点
Repeat() false true 保持活跃+触发下游(循环迭代)
Wait() false false 空转一周期(循环等下游消费)

1.4 L 值

  • BFS 从 NodeStart/NodeEntry 开始计算L 值显示在节点标题栏 (L:N)
  • 仅显示,不约束连线
  • L=-1 表示孤立节点(无路径可达)

1.5 防自循环

连线 A→B 时,从 B 出发沿现有边 DFS看能否回到 A。能回到则拒绝连线。


二、类型系统

2.1 连接器体系

IInput                      IOutput
  ├── Input<T>    (泛型)       ├── Output<T>   (泛型)
  └── InputAny    (动态)       └── OutputAny   (动态)

2.2 InputAny / OutputAny

特性 说明
初始状态 DataType = null,连接点显示灰色
连线锁定 连线后自动 LockType(T),连接点变为类型对应颜色
类型传播 锁定后 OnTypePropagated(T) → 同节点其他未锁定端口跟随
IsFixedType true 时阻止传播覆盖,如 NodeLerp.t 固定为 float
可改类型 LockType 允许覆盖(防止 NodeConst 切换类型后 DataType 不更新)

2.3 Input 拉取模型

  • Value 优先读 Output<T>._value,回退读 OutputAny
  • ConnectAny(IOutput) 支持 OutputAny → Input<T> 桥接(如 NodeConst → NodeMath.a
  • GetSourceNode() 兼容两种源

2.4 Output 反向写入

  • _writeBack 回调:NodeSet 通过 targetRef 修改 NodeVariable 的内部值

2.5 类型兼容表

from to 兼容
null * ✓(未锁定端口)
T T
int float
float int
其他 其他

2.6 类型颜色

类型 颜色
float
int
bool
string
Vector2
Vector3 绿
Color
GameElement 深紫
Signal
List<GameElement> 暗紫
null未锁定

三、节点目录

3.1 入口节点

节点 输入 输出 说明
NodeStart exec(Signal), element(GameElement) 图入口,绑定当前选中元素
NodeEntry exec(Signal) 纯信号入口

3.2 运算节点

节点 输入 输出 说明
NodeMath a(Any), b(Any, fixed) result(Any) +-*/ 四则,支持 float/int/V2/V3/Color/string
NodeLerp a(Any), b(Any), t(float,fixed) result(Any) 线性插值t 未连默认 0.5
NodeCompare a(Any), b(Any) result(bool) == != > < >= <=

3.3 向量节点

节点 输入 输出 说明
NodeSplit input(Any) x/y/z/w(float) V2 输出 xyV3 输出 xyzColor 输出 rgba
NodeCombine x/y/z/w(float) output(Any) UI 选类型后合并为 V2/V3/Color
NodeGetTransform element(GE) pos/rot/scl(V3) 读取元素变换
NodeSetTransform exec(Sig), element(GE), Pos/Rot/Scl(V3) 设置元素变换

3.4 数据节点

节点 输入 输出 说明
NodeConst value(Any) UI 选类型+填值6 种类型统一
NodeVariable<T> signal(Sig), set(T) get(T) 变量存储;signal 连着时等触发才更新
NodeSet targetRef(Any), value(Any) 反向写入 targetRef 指向的变量
NodeSelect cond(Any), true(Any), false(Any) result(Any) 二选一cond 未连用 UI Toggle

3.5 控制流节点

节点 输入 输出 说明
NodeBranch exec(Sig), cond(Any) true/false(Sig) cond>0 走 true否则 false
NodeForLoop exec(Sig), count(Any) loopBody(Sig), index(int), completed(Sig) 多周期交替输出→Wait→输出→Wait...

3.6 集合节点

节点 输入 输出 说明
NodeList<T> output(List<T>) 空列表
NodeListAdd<T> list(List<T>), item(T) output(List<T>) 追加元素
NodeListGet<T> list(List<T>), idx(UI) element(T) 索引取值
NodeForEach exec(Sig), list(Any) loopBody(Sig), current(Any), index(int), completed(Sig) 非泛型,连 List<X> 自动锁定 current 为 X

3.7 GameElement 操作

节点 输入 输出 说明
NodeGameElement exec(Sig), Root(GE), Source(GE) newElement(GE), completed(Sig) 复制粘贴元素
NodeChildByIndex parent(GE), idx(UI) child(GE) 子元素按索引
NodeChildCount parent(GE) count(int) 子元素个数
NodeClone exec(Sig), source(GE) clone(GE) Instantiate 克隆

3.8 调试节点

节点 输入 输出 说明
NodeDebugLog exec(Sig), value(Any) 带 Signal 等待的日志
NodeLog value(Any) 直接打印日志

四、所有节点统一规范

每个节点的 Loop() 遵循:

public override LoopResult Loop()
{
    // 1. 无输入直接 Complete
    // 2. EnsureInputsReady() — 所有已连输入的上游必须 Complete
    // 3. 取值 → 计算 → 设输出
    // 4. 返回 Complete / Repeat / Wait
}

EnsureInputsReady()NodeBase 上定义,自动检查 GetPrecedingNodes() 中所有上游的 Status。


五、UI 特性

5.1 节点外观

  • 半透明背景 + 标题栏 Name (L:N)
  • statusImageReady 灰 / Hang 橙黄 / Complete 绿
  • 选中节点蓝色高亮

5.2 连接线

  • UILineRenderer 贝塞尔曲线
  • 手动距离检测悬停(不依赖 Unity 射线)
  • 悬停加粗 +3px选中加粗 ×2
  • RectTransform 自动缩放到包围盒
  • 拖线时 dragLine 不参与射线

5.3 交互

操作 功能
左键空白 取消所有选中
左键节点 选中节点Shift 多选)
左键拖节点 移动节点
左键拖输出点→输入点 连线
左键线 选中线Shift 多选)
中键拖面板 平移整个画布
Ctrl+右键 右键菜单创建节点
Delete 删除选中

5.4 快捷键

快捷键 功能
F3 新建/销毁 NodeScript 编辑器
Enter 完整运行图
Shift+Enter 单步调试(首次初始化)
Esc 退出调试模式
Ctrl+Enter 运行图(保留)
F5 拓扑预览(打印分层执行计划)
F1 保存
F2 加载
Ctrl+C/V 复制/粘贴节点
Delete 删除选中

5.5 控制台命令

命令 说明
newNode 新建/销毁 NodeScript 编辑器
saveNode 保存到默认 graph.json
saveNode name 另存为 {name}.json
loadNode name {name}.json 加载

六、调试功能

6.1 单步调试 (Shift+Enter)

每步打印详细日志:

=== Step 3 ===
  ✓ NodeStart (L:0) → Complete
  ⏳ NodeMath (L:1) → Hang
  ▶ NodeBranch (L:2) → Ready
  triggers pending: 2, still running: 3

statusImage 同步变色。

6.2 拓扑预览 (F5)

═══ Topological Order (BFS layers) ═══
  Layer 0 (2 nodes, 3 downstream wires): Start(L:0), Entry(L:0)
  Layer 1 (1 nodes, 2 downstream wires): NodeMath(L:1)
  ...
  Unreachable (1 nodes): OrphanConst
  Total: 6 nodes, 5 wires, 3 layers

七、NodeManager 关键 API

方法 说明
Init(GameElement) 绑定元素 + 创建 Start 节点
RunGraph() 完整执行(生命周期循环)
ComputeLValues() 重算所有节点的 L 值 + 刷新标题
SaveToFile(string?) 保存图null 用默认路径
LoadFromFile(string?) 加载图
GetSavePath(string) 获取完整保存路径

八、文件存储

项目 路径
保存目录 Assets/StreamingAssets/NodeScript/
默认文件 graph.json
自定义文件 {name}.json

九、待完成 (Phase 4+)

  • Rect 容器(循环 / 子函数体内嵌区域)
  • 子控制器(循环体内节点独立调度)
  • NodeSubFunctionDef / NodeSubFunctionCall
  • Manager 扫描注册子函数定义