跳到主要内容

运行时架构

GCS · Runtime

GCS 运行时的分层结构:manager、状态机、状态视图、controller、流图执行、事件与表现层。

写自定义战斗 UI 或玩法代码之前先读这一页,让你的代码通过正确的入口修改状态,而不是直接改内部列表。

GCS 运行时把创作好的内容变成一场实时战斗。值得记住的边界只有一句话:内容资产描述可能发生什么,战斗状态存储此刻正在发生什么,而 controller 是改变这些状态的唯一安全通道。

运行时分层

主要类型职责对你代码的要求
ManagerGameCardManager, GCSApi持有当前启用的数据库、当前战斗、run master deck 和公开入口。外部代码从 GCSApi 开始。
State machineBattleStateMachine拥有战斗阶段、回合转换、选择等待、奖励等待和敌人回合。绝不强行改阶段。调用 StartBattleTryPlayCardEndPlayerTurn
State viewIBattleState, BattleStateView暴露回合、能量、单位、牌堆、已打出/已抽取历史和有效卡牌费用。通过 GCSApi.BattleGCSApi helper 读取。
ControllerIBattleController, BattleStateView修改生命、护甲、能量、状态、卡牌、延迟触发、变量和召唤敌人。通过 GCSApi 或 FlowGraph 节点修改,不要手动编辑列表和字段。
Flow executionGameCardFlowExecutor, EffectActionContext携带 source、target、card、battle、controller 和数据库运行卡牌/状态/敌人流图(FlowGraph)。图通过 context helper 和 controller action 读写。
EventsGCSEvents, IGCSEventChannel, GCSEventNames战斗状态变化时通知 UI、集成和自定义系统。GCSApi shortcut 或 typed named events 订阅。
PresentationUnitView, FloatingTextSystem, FX nodes, demo UI通过 UI、动画、VFX、SFX、浮动文本和镜头反馈展示状态变化。表现层只观察运行时结果,绝不拥有玩法规则。

公开入口

GCSApi 是文档化的运行时 facade。它的覆盖面刻意做得比较广,这样自定义 UI、示例代码、工具和玩法集成都不需要依赖内部类。

用它来做:

  • 启动和释放战斗。
  • 打出手牌并结束玩家回合。
  • 读取战斗阶段、回合、能量、单位状态、敌人意图、牌堆和状态层数。
  • 应用受控的状态修改。
  • 读取当前启用的数据库,按 GUID 查找内容。
  • 维护 run master deck。
  • 订阅事件。
  • 发现扩展注册表。

GCSApi.ManagerGCSApi.BattleGCSApi.Controller 为集成工作而暴露,但多数代码应优先使用命名 helper 方法。它们意图更清楚,遇到没有战斗时也会返回安全默认值。


读状态与改状态

GCS 把只读状态和可写控制分开。

表面类型能力
GCSApi.BattleIBattleState读取当前回合、能量、玩家、牌堆、存活敌人、已打出/已抽牌历史和有效卡牌费用。
GCSApi.ControllerIBattleControllerIBattleState 能读的全部内容,加上会走运行时规则的修改方法。
GCSApi helpersStatic methods为同一组常见读写提供安全、命名清晰的 shortcut。
注意

直接编辑 UnitState.StatusesCardPile.CardsUnitState.CurrentHp 会绕过 hooks、事件、UI 更新和校验。请使用 controller 背书的方法。


战斗状态模型

一场实时战斗包含:

状态含义
TurnNumber从 1 开始,每次敌人阶段结算后递增。
IsPlayerTurn玩家回合开始、行动、结束阶段为 true;敌人阶段为 false。
PlayerEnergy本回合还可用的能量。
PlayerUnit玩家的单位状态。
AliveEnemyUnits仍然存活的敌人。死亡单位会被排除。
HandPile, DrawPile, DiscardPile, ExhaustPile运行时卡牌区域。
PlayedThisTurn当前回合打出的卡牌,按打出顺序排列。
DrawnThisTurn当前回合抽到的卡牌,按抽牌顺序排列。

抽牌堆的顺序约定:最后一个元素就是下一张被抽到的牌。

Play Mode 下打开 Game Card Monitor 的 Battle 页签,就能实时看到这个模型:当前遭遇战、阶段、回合、玩家快照和敌人列表。

Game Card Monitor 的 Battle 页签,显示实时战斗快照、玩家状态和敌人列表


单位状态模型

UnitState 是战斗使用的实时单位记录。

字段或属性含义
UnitIdUI 和事件使用的运行时 id。
Source该单位背后的 GameUnit 创作资产。
CurrentHp, MaxHp当前和最大生命。
CurrentArmor当前护甲。
CurrentEnergy单位上的能量值。玩家本场战斗的能量池请读 GCSApi.PlayerEnergy
StatusesGameStatus 记录的运行时层数。
StatusAppliers每个状态由哪个单位施加(已知时记录)。
ActiveHooks状态和卡牌贡献的运行时 hooks。
WasAttackedThisTurn本回合该单位是否被攻击过。
SkipNextTurns待跳过的回合数。
IsDead当前 HP 小于等于 0 时为 true。
HpPercent当前 HP 占最大 HP 的整数百分比。

外部读取优先用 GCSApi.HpGCSApi.MaxHpGCSApi.ArmorGCSApi.HpPercentGCSApi.HasStatusGCSApi.StatusesOn


流图执行上下文

FlowGraph 运行时,GCS 会构建一个携带以下内容的执行上下文:

上下文值含义
Source对该行为负责的单位。
Host当前托管该行为的单位或拥有者。
Target已选择或已解析的目标。
Battle只读战斗状态。
Controller走运行时规则的修改表面。
Card图与卡牌相关时的当前卡牌实例。
Status database当前启用的状态查询。
Card database当前启用的卡牌查询。
Enemy unit database当前启用的敌人查询。

内置节点自动使用这个上下文。自定义节点同样应该通过 context 和 controller 读取输入、修改状态,不要走无关的全局查询。

想查看这个上下文如何进入实际执行,打开 Game Card Monitor 的 Flow 页签。执行器上报的每一次图运行都会在这里列出,最新的排在最前:

Game Card Monitor 的 Flow 页签,列出实时战斗中的 FlowGraph 执行记录


等待与异步表现

表现或玩家选择还在结算时,战斗状态机可以暂停推进。

机制用途
Choice waitChoice 节点暂停执行,直到玩家选择或跳过。
Animation gate动画和表现可以扣住阶段转换,直到 gated action 完成。
Flow waitWait 节点按秒或按 animation id 延迟后续执行。
Reward wait战斗胜利后,奖励选择让战斗保持等待,直到应用或跳过。

这也是为什么自定义 UI 应该响应事件和状态变化,而不是假设一次 API 调用会立即完成每个可见步骤。


事件是通知,不是状态存储

事件告诉系统刚刚变了什么。它们不是事实来源。自定义 UI 应该用事件判断何时刷新,然后通过 GCSApi 读取当前状态:

  1. 订阅相关事件。
  2. 在 handler 中从 GCSApi 读取当前状态。
  3. 更新 view model 或 UI widget。
  4. UI 销毁时释放订阅。

即使短时间内触发多个事件,UI 也能保持正确。


集成边界

需求推荐表面
自定义战斗 UIGCSApi read helpers 加 typed event shortcuts。
出牌控制GCSApi.CurrentHandGCSApi.CanPlayCardGCSApi.TryPlayCardGCSApi.RequiresTarget
单位面板GCSApi.Player()GCSApi.AliveEnemies()、单位 helper、HP/状态/意图事件。
内容浏览器GCSApi.CardsDecksPlayerUnitsEnemyUnitsStatusesEncountersFind* helper。
外部系统的运行时修改GCSApi mutation helpers 或 GCSApi.Controller
自定义事件桥接GCSApi.SubscribeGCSApi.EventsGCSApi.RaiseGameEvent,或 GES bridge events。

除非你就在改 demo 本身,否则不要依赖 sample hand views、reward views 或场景专属 presenter 这类 demo 专用组件。