跳到主要内容

战斗场景

Guide

Initialize System 创建可运行的战斗场景骨架,再按项目需要替换背景、单位布局、手牌、HUD 与表现组件

选定的 GameEncounter 交给 GameCardManager 后,场景对象会把玩家、敌人、牌堆与阶段状态呈现为可以操作的战场,无论战斗由 Bootstrap 固定启动,还是由项目流程动态启动,最终使用的都是同一组 Manager、Battle Runtime、Battle Canvas 与表现对象

初始化场景骨架

打开一个空场景,通过以下菜单进入 Game Card System 窗口,再点击 Initialize System

Tools > TinyGiants > GCS > Game Card System

命令执行完成后,Hierarchy 会形成一套可以继续指定 Encounter 与调整表现的场景骨架

干净的初始化场景 Hierarchy,包含 Main Camera、GameCardManager、EventSystem、Background、Battle Runtime 与 Battle Fx Directors

上图以六个根对象分别承接战斗启动、相机与输入、背景、单位与卡牌交互、HUD 和效果反馈,后续替换画面或接入项目流程时,可以沿着这份 Hierarchy 直接找到对应入口:

根对象核心组件在完整链路中的职责
Main CameraCameraAudioListenerPhysics2DRaycaster渲染世界空间战场,并把指针事件送给带 CardViewInput 的世界空间卡牌
GameCardManagerGameCardManagerGameCardEncounterBootstrap登记数据库、持有当前战斗状态,并在固定场景中提供默认 Encounter 启动入口
EventSystemEventSystemStandaloneInputModule将指针、Submit、Cancel 与按钮输入送入卡牌、HUD 和临时界面
BackgroundSpriteRendererBattleBackgroundFitBattleEncounterBackground填满相机画面,并为固定启动场景应用 Encounter 图标或职业背景
Battle Runtime战场、手牌、Canvas 与 Presentation 子对象将玩家、敌人、牌堆与战斗阶段转化为可操作的场景内容
Battle Fx DirectorsIntentThreatTelegraph在高威胁攻击意图出现时播放独立的视觉与声音提示
模板对象按根对象的精确名称判断场景是否已有对应内容
  • 除 Manager 会先按 GameCardManager 组件查找外,同名但内部残缺的 Battle Runtime 或其他模板根对象不会被整棵替换

  • 功能相同但名称不同的相机或 EventSystem 也不会被识别

  • 重复初始化前应先核对根对象名称与内部结构,避免残缺对象没有补齐或场景中出现两套相同服务,Background 的组件、排序与职业背景配置仍会按照上方规则补充或改写

从空场景完成初始化与 Encounter 配置的全部操作见第二场战斗,场景骨架确认无误后,再继续调整相机、输入与背景

配置相机、输入与背景

GameCardManager 将 Encounter 转为运行时战斗,Main CameraEventSystem 负责接收世界空间卡牌和 Screen Space UI 的输入,Background 则提供战场底图

对象模板默认值修改时需要保留的边界
Main Camera正交 Size 5,位置 (0, 0, -10),Viewport 铺满屏幕,开启 HDR 与 MSAA可以替换构图、Render Texture 或相机栈,继续使用世界空间卡牌输入时,负责事件相机的 Camera 需要保留 Physics2DRaycaster
EventSystem开启导航事件,Drag Threshold 10,输入轴为 HorizontalVerticalSubmitCancel可以换成项目自己的输入模块,场景中只保留一个启用中的 EventSystem
BackgroundSorting Layer 为 Background,Order -20,Overscan 1.01,Vignette Strength 0.3可以完整替换背景系统,最终渲染结果仍需位于单位、卡牌与 HUD 后方
动态启动不会自动切换背景

GCSApi.StartBattle 动态传入的 Encounter 不会触发这次背景切换,动态流程需要由场景协调器更新背景,或者先将 Encounter 同步到 Bootstrap.DefaultEncounter,再主动调用背景组件的 Apply

完整 Demo 会在单图背景之上使用 EncounterParallax 组织多图层动态效果,新初始化的场景只提供干净底图,便于直接替换为项目自己的视觉方案,完整的成品层级与动态效果见Demo 战斗场景

理解 Battle Runtime 层级

启动、输入与背景就绪后,Battle Runtime 会按玩家看到和操作的顺序展开单位、手牌、界面与反馈

🎬 Battle Runtime # 完整的战斗表现与交互根对象
├── ⚔️ Battle Board # 创建并摆放玩家与敌人单位视图
│ ├── 🦸 Player Area # 玩家单位的世界空间锚点
│ ├── 👹 Enemy Area # 按顺序排列敌人位置的父对象
│ │ ├── 1️⃣ Area1 # 第一名存活敌人的位置
│ │ ├── 2️⃣ Area2 # 第二名存活敌人的位置
│ │ └── 3️⃣ Area3 # 第三名存活敌人的位置
│ └── 🎯 Targeting Arrow # 从拖拽卡牌指向目标的视觉连线
├── 🃏 Hand # 手牌布局、对象池、指针输入与出牌展示
├── 🖥️ Battle Canvas # Screen Space HUD 与弹出界面的根对象
│ ├── 📊 HUD # 能量、牌堆、结束回合按钮与回合横幅
│ ├── 📚 Pile Inspector # 分页查看抽牌堆、弃牌堆与消耗牌堆
│ ├── 🔀 Choice Presenter # 显示流图候选项与确认控件
│ ├── 🎁 Reward View # 选择卡牌、能量、费用或跳过奖励
│ ├── 🏆 Result Popup # 胜利与失败结算面板
│ └── 🎭 Splash Screen # 展示遭遇战信息并延后启动战斗
├── 🗃️ Pile Cards # Pile Inspector 使用的世界空间卡牌容器
├── 🌫️ Pile World Blur # 打开牌堆时压暗后方战斗画面
├── 🃏 Choice Cards # 候选卡牌的世界空间容器
├── 🌫️ Choice World Blur # 选择期间压暗后方战斗画面
├── 🎁 Reward Cards # 奖励卡牌的世界空间容器
├── 🌫️ Reward World Blur # 显示奖励时压暗后方战斗画面
├── 🌫️ Result World Blur # 在结算面板后方压暗战斗画面
└── 🎛️ Presentation # 共享音频、VFX、文字、冲击与光标反馈
├── 🔊 Audio # 音乐、环境音、玩法音效与 Mixer 路由
├── 💥 VFX # 响应场景级与单位级特效请求
├── 💬 Floating Text # 伤害、治疗、状态与自定义战斗文字
├── ⏳ Delayed Trigger Indicator # 协调单位状态栏中的延迟触发图标
├── 💢 Impact Director # 统一调度顿帧与命中反馈
└── 🖱️ Cursor # 应用战斗光标贴图与缩放

配置单位区域与目标空间

一场战斗进入场景后,BattleBoard 会根据运行时状态创建玩家与敌人视图,将存活敌人依次放进可用区域,并同步处理 Tier 缩放、血条与状态偏移、意图位置、选中反馈和死亡隐藏时间

Battle Board Inspector,包含玩家与敌人区域、血条和状态偏移,以及 Normal、Elite、Boss、Summon 四档配置

Inspector 中可以直接看到玩家锚点、敌人父对象、三个默认敌人位置以及 Normal、Elite、Boss、Summon 四档视觉配置,截图之外的选择颜色、血条偏移与死亡节奏仍由同一个 BattleBoard 统一控制

配置模板值对战场的影响
Player AreaPlayer Area决定玩家单位视图的世界空间位置
Enemy Area RootEnemy Area作为整个敌方阵型的父对象
Enemy AreasArea1Area2Area3按顺序分配给存活敌人,同时显示四名以上敌人时需要增加位置
玩家区域位置(-5.2, 0)确定玩家一侧的版面锚点
敌人区域位置(5.2, 0)确定敌方一侧的版面锚点
敌人间距-1根据当前敌人数收紧或展开阵型
单位缩放Normal 0.4、Elite 0.5、Boss 0.6、Summon 0.35让不同 Tier 保持可辨认的视觉体量
意图 YNormal 1.4、Elite 2、Boss 2.4、Summon 1将意图 UI 放到对应体型上方
死亡隐藏延迟0.9 秒为死亡表现留出播放时间,再隐藏单位视图

Battle Board 上的 BattleOpeningEnemyTooltip 会把开场敌人说明锚定到 Enemy Area,模板允许它在没有 Splash Screen 时单独运行,逐字间隔为 0.026 秒,项目可以替换它的 Prefab、文本与节奏,不需要开场敌人说明时也可以直接停用该组件

配置手牌交互

单位视图和敌人位置建立以后,HandController 会把抽牌、悬停、拖拽、出牌区域与目标选择连接起来,并将成功打出的卡牌交给离场展示和对象池回收

Hand Inspector,显示 Hand Layout、Card View Pool、Card Fly Out Config 与 Card Play Showcase 的默认配置

截图中可见的四个组件分别负责手牌布局、视图池、离场路线与出牌展示,Inspector 下方的 HandController 继续连接输入、目标选择与战斗状态

组件模板默认值在交互链路中的职责
HandLayoutRadius 21.2、Max Angle 16、Spacing 3.296、Hover Scale 1.15、Tween 0.15 秒、Entrance 0.38 秒将手牌排成扇形,为悬停卡牌让位,并处理进入与重排动画
CardViewPoolBasic 卡牌 Prefab,Initial Per Bucket Size 4每个 Bucket 初始容量为 4,首次使用时按需创建视图,释放后回到池中复用
CardFlyOutConfigDefault、Basic、Burst 从 Bottom Right 离场,Skill、Support 从 Bottom Left 离场为不同卡牌类型选择左右离场方向,具体飞行过程由 CardPlayShowcase 完成
CardPlayShowcase进入 0.28 秒、停留 0.8 秒、飞出 0.65 秒、停留缩放 1.25在卡牌离场前完成聚焦展示,并记录尚未结束的展示数量
HandController抽牌间隔 0.27 秒、悬停宽限 0.08 秒、Target Pick Radius 1.6、屏幕下方 32% 为出牌区域连接指针输入、目标选择、Battle Board、对象池、手牌布局与出牌展示

卡牌尺寸变化会同时影响扇形间距、悬停高度、相邻卡牌切换与目标拖拽手感,调整 Prefab 后要把这些参数作为一组重新校准,卡牌进入与离开这些视图的规则见卡牌与牌堆生命周期

配置固定场景开场

Bootstrap.DefaultEncounter 已配置且 Auto Start On Play 开启时,模板 BattleSplashScreen 会先展示遭遇战信息,再启动战斗,并协调开场音频、发牌、敌人提示与回合横幅,它只读取 Bootstrap.DefaultEncounter,不能显示由 GCSApi.StartBattle 动态传入的 Encounter,因此,地图或任务动态选择 Encounter 时,需要禁用、移除或完整替换 Splash Screen,避免它继续读取并启动固定 Encounter,固定与动态入口的边界见战斗启动

配置常驻 HUD

战斗开始后,HUD 会持续显示当前资源与牌堆状态,并把结束回合和牌堆查看操作送回运行时

子对象组件玩家实际使用的功能
Energy DisplayUnitEnergyDisplay显示玩家当前能量
End Turn ButtonEndTurnButtonUIButtonSfx结束玩家回合,并播放按钮反馈
Draw PileDeckCounter显示数量并打开抽牌堆
Discard PileDiscardCounter显示数量并打开弃牌堆
Exhaust PileExhaustCounter显示数量并打开消耗牌堆
Turn BannerTurnBanner呈现玩家与敌人的回合切换,并在动画期间持有 Animation Gate

HUD 外观可以全部重做,新的按钮与计数控件仍需调用结束回合与牌堆查询接口,不依赖模板 Prefab 的连接方式见自定义 UI 接入

配置临时界面

牌堆查看、FlowGraph Choice、胜利奖励与最终结果不会同时常驻屏幕,它们会在对应状态到来时接管输入,并配合前面的 World Holder 与 Blur Sprite 组织世界空间卡牌

触发时机子对象与组件模板配置与运行边界
玩家查看牌堆时Pile InspectorCardPileInspector每页 5 × 2 张卡牌,卡牌缩放 0.34,复用 CardViewPool 浏览抽牌堆、弃牌堆与消耗牌堆
FlowGraph 进入 Choice 时Choice PresenterBattleChoicePresenter卡牌缩放 0.34,将候选项、确认与跳过操作回传给 FlowGraph,场景缺少 Presenter 时 Choice 会直接进入 Skipped 分支,不会保留一层空白等待界面
胜利并发出 OnBattleRewardOfferedReward ViewCardRewardView卡牌缩放 0.4,两段揭示延迟均为 0.5 秒,选择卡牌、能量、费用或跳过后调用 ApplyRewardSkipReward
失败结束,或胜利奖励完成并发出 OnBattleEndedResult PopupBattleResultPopup胜利与失败延迟为 0.9/1.0 秒,打字速度为每秒 42 个字符
提示
  • Choice Presenter 负责完成 FlowGraph 等待的用户选择,Reward View 负责提交奖励结果、解除 IsWaitingForReward 并让战斗发出 OnBattleEnded

  • 替换这两个界面时必须保留对应回调,奖励界面不能只关闭视觉对象而不提交奖励结果

  • 场景中只保留一个 IChoicePresenter 实现,Manager 会连同未启用对象一起查找 Presenter,同时保留模板组件与自定义组件时无法保证选中顺序,替换 Choice UI 时需要移除旧组件,不能只停用旧 GameObject

配置表现反馈

当出牌、状态变化与阶段切换已经正确运行,Presentation 会把这些结果转化为音频、场景特效、浮动文字与冲击反馈,玩家由此能够判断刚才发生了什么,而不必只盯着数值变化

对象组件负责的反馈
Presentation/AudioBattleAudio管理卡牌、UI、战斗、结算、音乐、Mixer、音量与玩法音频
Presentation/VFXBattleVFXPresenter响应战斗开始、玩家回合、敌人回合与战斗结束事件,播放场景级 Ambient、BattleStart、TurnStart、Victory 与 Defeat VFX
Presentation/Floating TextBattleFloatingTextPresenter显示伤害、治疗、状态与自定义战斗文字
Presentation/Delayed Trigger IndicatorUnitDelayedTriggerIndicator在现有单位状态栏中为每个待执行触发器协调一枚独立倒计时图标
Presentation/Impact DirectorBattleImpactDirector统一处理顿帧与命中冲击反馈
Presentation/CursorBattleCursor应用战斗光标纹理,模板缩放为 2
Battle Fx DirectorsIntentThreatTelegraph任一 Attack 意图值达到或超过 12 时,在敌人上方 0.9 单位处播放威胁 VFX,并以 0.7 音量播放提示音

UnitDelayedTriggerIndicator 只负责协调状态栏,不再绘制独立的头顶沙漏文本徽标;每个待执行触发器都有自己的图标,依次使用登记时捕获的卡牌图标、状态图标或来源单位图标,并叠加剩余回合数字;目标仍存活且仍在战斗中时图标归入目标状态栏,目标死亡或离场后回退到来源状态栏

悬停图标会显示名称、描述、触发阶段与剩余回合;多个触发器按剩余回合、阶段、TriggerId 排序,战斗结束时清空全部延迟触发图标

FlowGraph 的 Play VFX 节点会直接实例化节点自身配置的 Prefab,不经过 BattleVFXPresenter,因此节点效果与场景阶段特效可以独立替换,音频、VFX 与浮动文字的节点行为见FX 节点,等待参数见流程节点

提示
  • Audio、VFX、Floating Text、Delayed Trigger Indicator、Impact Director、Cursor 与 Intent Threat Telegraph 可以按项目风格逐项替换或移除,移除后只会缺少对应反馈,不会改变运行时结算

  • Splash Screen、Hand、HUD、Choice 与 Reward 承担启动、交互或运行回调,新的实现必须继续启动正确的 Encounter,并提交出牌、结束回合、Choice 选择与 Reward 结果

阶段停止推进时,先确认正在等待的对象

  • AnimationGate 通过 Holder 计数等待表现释放

  • Choice 通过 IsWaitingForChoice 等待选择回调

  • Reward 通过 IsWaitingForReward 等待奖励提交

  • CardPlayShowcase.ActiveCount 只会让奖励与结算画面等待卡牌展示结束