跳到主要内容

表现层

Guide

运行时状态如何到达 UI、单位视图、VFX、音频和浮动文本,以及为什么玩法从不等待缺失的视觉资产

Hunter 战斗中 Poison Arrow 刚结算完的画面:敌人 HP 下降、Poison 层数图标出现、能量已消耗、卡牌进入弃牌堆

表现边界

区域拥有不拥有
RuntimeHP、护甲、能量、牌堆、状态、阶段、事件像素布局、声音路由、粒子质量
UI手牌 widget、单位血条、状态图标、意图 widget、选择/奖励面板战斗规则或出牌合法性
Unit view单位 sprite、程序化运动、受击/治疗/死亡反应、状态视觉伤害计算或状态层数
FX nodesVFX、SFX、浮动文本、闪烁、滑动、震屏、动画的请求最终资产打磨、渲染管线兼容、mixer 设置

即使视觉效果播放失败,玩法也照常结算

事件驱动的 UI

反应式循环始终是同一套:controller 修改状态并触发事件,你的 handler 被唤醒,通过 GCSApi 读取最新状态,再更新 widget

自定义 UI 应该订阅运行时事件,然后读取当前状态:

private IDisposable _energySub;

void OnEnable()
{
_energySub = GCSApi.OnEnergyChanged(_ => RefreshEnergy());
RefreshEnergy();
}

void OnDisable()
{
_energySub?.Dispose();
}

void RefreshEnergy()
{
energyLabel.text = $"{GCSApi.PlayerEnergy}/{GCSApi.MaxEnergy}";
}

事件告诉你什么时候该刷新,GCSApi 告诉你当前值是什么

核心 UI 刷新事件

UI 区域监听事件读取状态
回合与阶段标签OnTurnStartedOnTurnEndedOnEnemyTurnStartedOnBattleEndedGCSApi.PhaseGCSApi.TurnNumberGCSApi.IsPlayerTurn
能量OnEnergyChangedOnEnergyGainedOnEnergySpentGCSApi.PlayerEnergyGCSApi.MaxEnergy
手牌卡牌生命周期事件、OnCardModifiedOnEnergyChangedGCSApi.Hand()GCSApi.CanPlayCardGCSApi.GetEffectiveEnergyCost
单位条OnUnitHpChangedOnArmorGainedOnArmorLostOnUnitDiedGCSApi.HpGCSApi.MaxHpGCSApi.ArmorGCSApi.IsAlive
状态 widgetOnStatusChangedOnStatusTicked、状态 transition 事件GCSApi.StatusesOn(unit)
敌人意图OnEnemyUnitIntentChangedOnEnemyPhaseChangedGCSApi.PendingIntentsGCSApi.CurrentIntentTagGCSApi.CurrentIntentValue
选择 UIOnEffectChoiceOfferedOnEffectChoiceSelectedOnEffectChoiceSkippedChoice payload 加 GCSApi.IsWaitingForChoice
奖励 UIOnBattleRewardOfferedOnBattleRewardSelectedOnBattleRewardSkippedReward payload 加 GCSApi.IsWaitingForReward

UnitView 行为

内置的 UnitView 绑定到一个 UnitState,并订阅:

  • OnUnitHpChanged
  • OnUnitDied
  • OnStatusChanged
  • OnStatusTicked

它用这些事件播放受击、治疗、死亡和状态动画,同时按 UnitId 注册自身,让表现节点能找到目标单位的 view

自定义项目可以复用 UnitView、派生自己的 view 行为,或整个替换掉它,稳定的集成点是运行时事件 payload 加 UnitId

浮动文本

FloatingTextSystem 暴露一个表现请求事件:

请求字段含义
Target接收文本的单位
KindDamage、Heal、Armor、Block 或 Custom
ContentAmount 或 Text
Amount要显示的数字
Text自定义标签
Color, UseCustomColor可选的颜色覆盖
IncludeSign是否显示正负号
ScaleMultiplier, DurationMultiplier单次请求的视觉微调
Offset目标附近的位置偏移

FlowGraph 的 Show Floating Text 节点会发出这些请求,自定义浮动文本 presenter 可以订阅 FloatingTextSystem.Requested

FlowGraph 表现节点

节点运行时效果
Play VFX在单位或位置上实例化或请求 VFX prefab
Play Animation向目标单位的表现发送 animation trigger
Play SFX播放一次性的 audio clip
Flash Unit目标 view 存在时调用 UnitView.Flash
Slide Unit短暂移动目标的表现
Show Floating Text发送 FloatingTextRequest
Shake Camera请求镜头震动

在玩法状态改变之后再用这些节点,让视觉反映真实结果

动画 Gate 与等待

状态机可以推迟转换,等表现类等待完成

功能用途
Animation gate在 gated coroutine 或动画运行期间扣住阶段转换
Flow wait让图按秒或按 animation id 延迟后续执行
Enemy gaps在敌人行动之间加入可读的间隔

Game Card Monitor 的 Gate 页签显示当前谁持有 animation gate、acquire/release 日志和超时时间,用于定位卡住的转换:

Game Card Monitor 的 Gate 页签,显示当前 animation gate 的持有者与 acquire/release 日志

这也是自定义 UI 应该反应式处理状态变化的原因,一次出牌可能引发状态变化、动画、等待、选择和后续转换

VFX、音频与渲染管线范围

表现的图契约是稳定的,最终资产则是另一回事:

  • VFX prefab 可以之后替换或升级
  • SFX clip 和 mixer 路由可以之后配置
  • 渲染管线相关内容(材质、shader、后处理)属于资产层,不属于图

玩法图只请求需要的反馈,具体渲染由资产和表现层决定,这样切换渲染管线时不需要修改玩法图

失败行为

缺失项预期结果
缺少 unit view玩法照常结算;针对该单位的视觉请求可能被跳过
缺少 VFX prefab玩法照常结算;没有粒子出现
缺少 SFX clip玩法照常结算;没有声音
缺少浮动文本 presenter玩法照常结算;请求没有可见的订阅者
Animation wait 未安排执行立即继续

运行时日志和 Monitor 用于诊断表现缺失,可选表现资产没有配置时,战斗仍应继续结算