自定义节点示例
GCS 随包提供三个自定义节点样例:一个起步模板、一个带条件的状态修改节点,以及一个纯数值节点
GCS 的自定义节点样例位于:
Assets/TinyGiants/GameCardSystem/Samples~/CustomNodes/
Unity 会忽略名字以 ~ 结尾的文件夹,所以这些文件以参考源码的形式随包发布,不会就地编译,把需要使用的 .cs 文件复制进你自己的 runtime assembly 再构建,每个样例都保持较小范围,完整覆盖 public 扩展面:[Serializable]、[FlowNode]、节点基类、推断字段、声明端口和 context helper
FlowNodeTemplate
FlowNodeTemplate.cs 是覆盖面最广的起点:所有必需部件集中在一个文件里,注册为 Action / Your Node Name
| 部件 | 用途 |
|---|---|
[Serializable] | 让 Unity 把节点实例保存进 FlowGraph 资产 |
[FlowNode("Action", "Your Node Name")] | 把节点加入 Add Node 菜单 |
MutatorNode | 在 Execute 里运行可写的战斗逻辑 |
UnitSource TargetSource | 自动创建 Target 单位输入(默认 Opponent) |
int Amount | 自动创建 Amount scalar 输入 |
DamageStyle Style | 枚举配置行,显示在节点上而不是端口 |
INodePorts | 声明字段推断造不出来的 Result 输出 |
ctx.PullInputOr | 读接线值,回落到节点字段 |
ctx.ResolveUnits | 同时支持目标下拉和已接线的目标端口 |
ctx.Controller.DealDamage | 通过受支持的通道修改战斗状态 |
ctx.StoreResult | 把声明好的 Result 输出发布给下游节点 |
节点会改战斗状态、还可能暴露输出时,从这里开始
安全的改动:
- 改 category 和 display name
- 用项目实际需要的配置字段替换
TargetSource、Amount和枚举 - 用你的节点实际执行的战斗改动替换 controller 调用
- 在还没有已保存内容连接它之前,重命名 result 输出
高风险的改动:
- 移除
[Serializable] - 把文件挪进 editor-only assembly
- 直接改单位、卡牌或牌堆字段
- 已保存的图连上字段或输出之后再重命名它们
HealIfBelowHalfNode
HealIfBelowHalfNode.cs 展示一个完整卡牌效果节点:治疗选中的单位,并可以限制为只治疗半血及以下的单位
| 字段 | FlowGraph 中显示什么 |
|---|---|
TargetSource | 谁能被治疗,默认 Self,可以暴露并接线 |
HealAmount | 恢复多少 HP,固定值或接线输入 |
OnlyBelowHalf | 半血条件是否生效 |
它的行为:
HealAmount通过ctx.PullInputOr(this, nameof(HealAmount), HealAmount)读取- 目标来自
ctx.ResolveUnits(this, TargetSource, nameof(TargetSource)) - 死亡和 null 单位被跳过,半血检查比较每个目标的当前 HP 和最大 HP
- 治疗走
ctx.Controller.GainHp Healed输出发布的是实际恢复的 HP,按治疗前后差值统计,满血目标贡献 0
项目专属动作可以参考这个模式:按自定义条件治疗友方、对被标记的敌人加成伤害、按已损失 HP 获得护甲,或者统计有多少目标通过检查并把数量传下去
AddValuesNode
AddValuesNode.cs 是最小的纯值样例,注册为 Operator / Add Values:读两个输入,返回它们的和
| 字段 | 含义 |
|---|---|
A | 第一个数字,字段作回落值 |
B | 第二个数字,字段作回落值 |
它的行为:
- class 继承
OperatorNode,从不调用ctx.Controller - 用
NodePort.ResultOut("Result", PortDataType.Int)声明Result - 从
Evaluate(IEvaluationContext ctx, string outPort)返回和
数学、比较、分数计算、转换器,以及任何要接进其他节点输入的项目公式都可以采用这个模式,有多个输出的节点逐个声明,然后按 outPort 分流:
public override object Evaluate(IEvaluationContext ctx, string outPort)
{
int value = ctx.PullInputOr(this, nameof(Value), Value);
return outPort == "Double" ? value * 2 : value;
}
推荐的起始样例
| 你想做的 | 从这里开始 |
|---|---|
| 改状态的卡牌效果 | HealIfBelowHalfNode 或 FlowNodeTemplate |
| 计算值 | AddValuesNode |
| 自定义 selector | AddValuesNode,基类换成 SelectorNode,返回单位或卡牌 |
| 自定义分支节点 | FlowNodeTemplate,基类换成 ControlNode,声明 ControlOut 端口 |
| 表现节拍 | FlowNodeTemplate,基类换成 VfxNode,实现 Play |
验证改造后的节点
- Unity 无 C# 错误编译通过
- 节点出现在 Add Node 菜单里它的
[FlowNode]category 下 - scalar 字段显示为可编辑值,并且能暴露成端口
<Name>Source字段暴露出对应的单位或卡牌输入- 声明的 result 输出可见,能连给下游
- 测试战斗在 Monitor 里显示预期的状态变化
打开 Monitor 的 Flow 标签页,确认自定义节点已经执行,每次 FlowGraph 运行都会记录触发器、节点数和耗时,打出经过该节点的卡牌后,列表中会新增一条执行记录:

节点能编译但行为异常时,先用固定字段值测试,再接动态端口,固定版本正确之后,一次只暴露一个端口
常见错误
| 症状 | 可能原因 |
|---|---|
| Add Node 里找不到节点 | 缺 [FlowNode]、class 是 abstract,或程序集没引用 TinyGiants.GCS.Runtime |
| 接线值被忽略 | 代码直接读字段,没走 ctx.PullInputOr |
| 接线目标被忽略 | 代码跳过了 ctx.ResolveUnits / ctx.ResolveCards |
| 输出连不上线 | 输出从未用 NodePort.ResultOut 或 NodePort.Out 声明 |
| 输出值永远缺失 | StoreResult 的名字和已声明输出名对不上 |
| 事件和视觉都不触发 | 代码直接改战斗对象,没调用 ctx.Controller |