跳到主要内容

战斗场景

Guide

Initialize System 仅用六个根对象便搭好了一整套可运行的战斗表现层,这是倾注心血的设计

选定的 GameEncounter 交给 GameCardManager 后,六个根对象会把玩家、敌人、牌堆与阶段状态呈现为可以看见和操作的战场,无论战斗由 GameCardEncounterBootstrap 固定启动,还是由地图、关卡或任务调用 GCSApi.StartBattle 动态启动,最终接管战斗的都是同一组 GameCardManagerBattle RuntimeBattle Canvas 与表现对象

Initialize System 建立场景骨架

打开一个空场景,通过以下菜单进入 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 # 应用战斗光标贴图与缩放

Battle Board 先建立单位与目标空间

一场战斗进入场景后,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、文本与节奏,不需要开场敌人说明时可以直接停用该组件

Hand 再把卡牌操作接入战场

单位视图和敌人位置建立以后,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 后要把这些参数作为一组重新校准,运行时卡牌进入与离开这些视图的规则见手牌与三类牌堆

固定场景先由 Splash Screen 编排开场

Bootstrap.DefaultEncounter 已配置且 Auto Start On Play 开启时,BattleSplashScreen 会在 Awake 中关闭 Bootstrap 在本次运行中的直接自动启动,先展示遭遇战信息,再延后调用 StartBattle。开场音频、发牌、敌人提示与回合横幅也由这套开场流程协调,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 会把这些结果转化为音频、场景特效、浮动文字与冲击反馈,玩家由此能够判断刚才发生了什么,而不必只盯着数值变化

对象组件负责的反馈
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 音量播放提示音

FlowGraph 的 Play VFX 节点会直接实例化节点自身配置的 Prefab,不经过 BattleVFXPresenter

节点效果与场景阶段特效可以独立替换,音频、VFX、浮动文字与 Gate 的接入边界见表现层

提示
  • 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 只会让奖励与结算画面等待卡牌展示结束