跳到主要内容

样例讲解

GCS · Extending GCS

三个随包文件把扩展面从头覆盖到尾:一个可复制粘贴的模板、一个带条件的真实卡牌效果、一个纯值节点。

面向希望从可运行代码开始理解节点扩展面的程序员。

GCS 的自定义节点样例位于:

Assets/TinyGiants/GameCardSystem/Samples~/CustomNodes/

Unity 会忽略名字以 ~ 结尾的文件夹,所以这些文件以参考源码的形式随包发布,不会就地编译。把需要使用的 .cs 文件复制进你自己的 runtime assembly 再构建。每个样例都保持较小范围,完整覆盖 public 扩展面:[Serializable][FlowNode]、节点基类、推断字段、声明端口和 context helper。


推荐工作流

  1. 把一个样例文件从 Samples~ 复制到你自己的项目代码里
  2. 放进引用了 TinyGiants.GCS.Runtime 的 runtime assembly
  3. 把 namespace 改成你项目的
  4. 重命名 class 和 [FlowNode] 的 display name
  5. 用做卡作者应该看到的选择替换字段
  6. context 读取保持用 PullInputOrResolveUnitsResolveCards
  7. 战斗改动保持在 ctx.Controller
  8. 等 Unity 编译,然后在 Add Node 菜单里找到节点

先复制再改还可以避免包更新覆盖你的游戏专属节点。


FlowNodeTemplate

FlowNodeTemplate.cs 是覆盖面最广的起点:所有必需部件集中在一个文件里,注册为 Action / Your Node Name

部件用途
[Serializable]让 Unity 把节点实例保存进 FlowGraph 资产
[FlowNode("Action", "Your Node Name")]把节点加入 Add Node 菜单
MutatorNodeExecute 里运行可写的战斗逻辑
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
  • 用你自己的面向作者字段替换 TargetSourceAmount 和枚举
  • 用你的节点实际执行的战斗改动替换 controller 调用
  • 在还没有已保存内容连接它之前,重命名 result 输出

高风险的改动:

  • 移除 [Serializable]
  • 把文件挪进 editor-only assembly
  • 直接改单位、卡牌或牌堆字段
  • 已保存的图连上字段或输出之后再重命名它们

HealIfBelowHalfNode

HealIfBelowHalfNode.cs 是普通卡牌效果的最佳样例。它建模一个用户可见行为:治疗选中的单位,可选只治疗半血及以下的。

字段作者看到什么
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;
}

从哪个样例起步

你想做的从这里开始
改状态的卡牌效果HealIfBelowHalfNodeFlowNodeTemplate
计算值AddValuesNode
自定义 selectorAddValuesNode,基类换成 SelectorNode,返回单位或卡牌
自定义分支节点FlowNodeTemplate,基类换成 ControlNode,声明 ControlOut 端口
表现节拍FlowNodeTemplate,基类换成 VfxNode,实现 Play

验证改造后的节点

  1. Unity 无 C# 错误编译通过
  2. 节点出现在 Add Node 菜单里它的 [FlowNode] category 下
  3. scalar 字段显示为可编辑值,并且能暴露成端口
  4. <Name>Source 字段暴露出对应的单位或卡牌输入
  5. 声明的 result 输出可见,能连给下游
  6. 测试战斗在 Monitor 里显示预期的状态变化

Monitor 的 Flow 页是确认节点实际运行过的最快方式。每次图执行都会连同触发器、节点数和耗时一起被捕获;一张打出后经过你节点的卡,会在列表中显示为一行记录:

Monitor 的 Flow 页捕获一次 Poison Arrow 出牌:触发器 OnCardPlayed,执行 10 个节点,附带耗时

节点能编译但行为异常时,先用固定字段值测试,再接动态端口。固定版本正确之后,一次只暴露一个端口。


常见错误

症状可能原因
Add Node 里找不到节点[FlowNode]、class 是 abstract,或程序集没引用 TinyGiants.GCS.Runtime
接线值被忽略代码直接读字段,没走 ctx.PullInputOr
接线目标被忽略代码跳过了 ctx.ResolveUnits / ctx.ResolveCards
输出连不上线输出从未用 NodePort.ResultOutNodePort.Out 声明
输出值永远缺失StoreResult 的名字和已声明输出名对不上
事件和视觉都不触发代码直接改战斗对象,没调用 ctx.Controller