26 KiB
CombatNode 设计规范(开发约束)
最后更新:2026-03-12
1. 适用范围与目标
本文描述 CombatNode 域的后续开发标准。
说明:
- 本文是“目标架构约束”,不要求当前代码已经完全达成。
- 后续新增功能、重构、拆分类、review 职责边界时,以本文为准。
- 如果当前实现与本文不一致,新增代码优先向本文收敛,而不是继续扩大旧结构。
核心目标:
CombatScheduler收敛为“状态机管理器”,不再继续堆积加载、结算、奖励选择等业务细节。- 战斗内资源收口到独立资源服务,由内部管理,不再由
CombatNodeComponent直接持有真值。 MapEntity通过MapData + Event获取战斗上下文,不反查CombatNode域内部状态。
2. 架构总览
2.1 CombatNodeComponent(入口 Facade)
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs
长期职责:
- 读取并缓存
DRLevel / DRLevelPhase / DRLevelSpawnEntry。 - 按主题筛选关卡。
- 启动/停止
CombatScheduler。 - 对外暴露只读运行时属性。
- 提供少量用户入口,例如
StartCombat、TryEndCombatByPlayer。
长期不负责:
- 不直接持有
Coin / Gold / BaseHp / Loot Backpack的真值。 - 不直接缓存本局建塔属性快照。
- 不直接发布战斗流程事件。
- 不直接处理敌人掉落、结算、奖励选择、地图加载。
2.2 CombatScheduler(状态机管理器)
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatScheduler.cs
长期职责:
- 持有共享运行时数据与共享服务实例。
- 管理状态实例。
- 提供统一的
ChangeState(...)状态迁移入口。 - 提供敌人事件的公共处理入口。
- 作为状态机生命周期边界,统一做运行时重置。
长期不负责:
- 不直接硬编码加载流程。
- 不直接硬编码结算流程。
- 不直接硬编码奖励选择 UI 逻辑。
- 不直接硬编码
PhaseEndType结束条件。
推荐状态类命名:
CombatLoadingStateCombatRunningPhaseStateCombatWaitingForPhaseEndStateCombatSettlementStateCombatRewardSelectionStateCombatFinishFormStateCombatWaitingForReturnStateCombatFailedState
实现约束:
- 上述状态类可以作为
CombatScheduler的嵌套类实现,也可以拆成独立文件;但必须只服务于CombatScheduler状态机,不形成独立业务边界。 - 共享数据与共享服务统一收口到
CombatScheduler内部持有的运行时承载体,不允许散落在各状态类中。 - 若
CombatScheduler体量过大,允许在其内部实现中继续拆出:CombatSchedulerRuntime:承载共享运行时字段与共享服务引用CombatSchedulerCoordinator:承载多个状态共用的流程辅助方法
- 上述拆分只属于
CombatScheduler的内部实现细化,不改变CombatScheduler作为唯一状态机边界的职责。 - 所有状态切换只能通过
CombatScheduler.ChangeState(...)完成。 - 状态类不能彼此直接操控。
2.3 EnemyManager(敌人域 Facade)
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemyManager.cs
长期职责:
- 对状态机提供统一敌人域接口。
- 编排敌人子服务。
- 暴露只读事实:
AliveEnemyCountIsPhaseSpawnCompletedHasAliveBoss
- 在敌人死亡或到家时,通过公共入口向
CombatScheduler上报:OnEnemyDefeated(DREnemy enemy)OnEnemyReachedBase(DREnemy enemy)
长期不负责:
- 不直接给资源入账。
- 不直接扣基地血量。
- 不直接决定状态切换。
3. 状态机模型
3.1 状态列表(目标)
LoadingRunningPhaseWaitingForPhaseEndSettlementRewardSelectionFinishFormWaitingForReturnFailed
说明:
- 正常结束流只有一条状态链:
Settlement -> RewardSelection(可选) -> FinishForm -> WaitingForReturn
- 正常通关、玩家主动结束、基地血量归零都走同一条结束链。
Failed仅用于异常失败,不用于“基地被击破”这类正常战斗失败。
3.2 CombatLoadingState
职责:
- 通过
CombatLoadSession执行地图与基础战斗 UI 加载。 - 从局内资源管理器读取本局快照。
- 组装
MapData并发起ShowEntity(MapEntity)。
约束:
- 只负责加载,不负责初始化局内资源。
- 局内资源必须在进入状态机前初始化完成。
3.3 CombatRunningPhaseState
职责:
- 执行当前
DRLevelPhase的行为。 - 推进
SpawnEntry时序与出怪。 - 管理
EnemySpawnDirector的阶段级初始化与重置。 - 在新 phase 开始时发布:
CombatProcessEventArgsCombatEnemyHpRateChangedEventArgs
退出条件:
- 当前 phase 的所有
SpawnEntry已执行完毕时,进入WaitingForPhaseEnd。 - 若共享“结束战斗请求标记”已置位,也可结束当前运行态并转入正常结束链。
不负责:
- 不根据
PhaseEndType判断 phase 是否真正结束。 - 不直接根据
BaseHp或敌人死亡事件切状态。
3.4 CombatWaitingForPhaseEndState
职责:
- 不再生成新敌人。
- 根据
PhaseEndType判断当前 phase 是否结束。
约束:
PhaseEndType的判断由独立判定服务负责,不在状态内硬编码。- 每种
PhaseEndType对应一个实现类。 - 该判定服务为本状态专用,不作为全局共享服务常驻在
CombatScheduler上。
3.5 CombatSettlementState
职责:
- 进入时统一构造结算上下文。
- 根据共享资源状态完成结算修正。
- 决定后续进入
RewardSelection还是FinishForm。
负责的逻辑包括:
- 基地血量奖励/惩罚。
- 满血奖励选择的准入判断。
- 生成最终展示摘要。
- 准备待合并的结算背包快照。
约束:
- 不依赖单独的
CombatEndReason字段。 BaseHp <= 0表示基地被击破。- 正常通关与玩家主动结束在结算产出上不区分原因。
3.6 CombatRewardSelectionState
职责:
- 绑定、配置、打开、关闭
RewardSelectForm。 - 处理奖励选择过程。
- 将奖励选择结果写入“结束状态链持有的结算上下文”。
约束:
- 不重新判断“是否应该出现奖励选择”。
- 只处理选择过程本身。
3.7 CombatFinishFormState
职责:
- 绑定、配置、打开、关闭
CombatFinishForm。 - 读取结算上下文并展示最终结算结果。
3.8 CombatWaitingForReturnState
职责:
- 等待玩家从结算返回。
- 完成地图与战斗基础 UI 清理。
- 完成正常退出收尾。
- 在整场战斗真正退出时发布
NodeCompleteEventArgs。
3.9 CombatFailedState
职责:
- 表示异常失败。
- 保存并展示错误信息。
- 执行异常收尾与剩余资源回收。
约束:
Failed只处理异常路径。- “基地血量为 0”不进入
Failed。
4. 共享服务与推荐命名
4.1 命名后缀词典
Scheduler:只用于状态机边界或阶段推进总控,例如CombatScheduler。Manager:只用于子域 Facade/聚合入口,例如EnemyManager。Coordinator:只用于跨状态、跨服务的流程编排,不持有独立业务真值。Service:只用于聚焦业务行为,不承担框架事件桥接或异步句柄跟踪。Calculator:只用于纯计算与结果组装,不直接提交状态或驱动 UI。Session:只用于一次加载/交互过程的生命周期对象。Bridge:只用于框架边界适配器。Runtime:只用于运行时可变状态承载。Context:只用于被动数据包或共享上下文。Result:只用于动作输出或结算产出;若外围服务名已表达动作语义,不再重复动作前缀。Flags:只用于聚合布尔控制项,不承载流程编排逻辑。Resolver:只用于映射、查找、判定、解析职责。Tracker:只用于跟踪运行中的实体或事实真值。Port:只用于向内部状态或 use case 暴露的受限宿主接口。
4.2 CombatLoadSession
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatLoadSession.cs
长期定位:
- 长期保留的独立加载服务。
- 专门负责地图与战斗内基础 UI 的加载/清理。
职责:
- 加载地图实体。
- 打开/关闭
CombatInfoForm。 - 跟踪加载成功/失败状态。
- 对外提供
CurrentMap与IsReady。
4.2.x CombatSchedulerRuntime / CombatSchedulerCoordinator(实现细化)
当前实现允许:
- 用
CombatSchedulerRuntime承载所有状态共享的运行时字段与共享服务引用。 - 用
CombatSchedulerCoordinator承载多个状态共用的流程辅助逻辑。
约束:
- 两者都必须由
CombatScheduler持有并统一管理生命周期。 - 两者都不替代
CombatScheduler对外暴露状态机边界。 Runtime不负责状态切换。Coordinator不持有独立业务真值,只能围绕共享运行时做编排辅助。- 状态类只允许通过
Runtime + Coordinator访问共享状态与共享流程,不应再直接耦合其他状态实现细节。
4.3 PhaseLoopRuntime
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/PhaseLoopRuntime.cs
长期定位:
- 长期保留的独立 phase runtime 服务。
职责:
- 维护当前
DRLevelPhase。 - 维护
DisplayPhaseIndex、PhaseCount。 - 维护统一的 phase 时间基准,例如
phaseElapsedTime或phaseStartTime。 - 负责进入下一 phase。
- 持有统一“请求结束战斗”标记。
约束:
- 只做 phase 运行时数据管理,不直接切状态。
4.4 CombatRunResourceStore
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatRunResourceStore.cs
目标职责:
- 持有本局
Coin真值。 - 持有本局累计
Gold真值。 - 持有本局
BaseHp真值。 - 持有本局战利品背包。
- 持有本局建塔属性快照。
- 提供只读快照给结束状态链与加载状态使用。
- 发布资源变化事件:
CombatCoinChangedEventArgsCombatBaseHpChangedEventArgs
初始化约束:
- 在进入状态机前完成初始化。
- 由内部从
PlayerInventory获取并缓存本局建塔快照。
事件约束:
Coin / BaseHp变化事件同时携带“当前值”和“变化量”。Gold只是结算累计值,不要求战斗内实时事件驱动。
4.5 InventoryGenerationComponent
文件:Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/InventoryGenerationComponent.cs
目标职责:
- 作为局外组件产出的统一运行时入口。
- 对外提供:
BuildShopGoods(...)ResolveEnemyDrop(...)BuildRewardCandidates(...)
- 在内部编排:
DropPoolRollerRewardCandidateBuilderOutGameDropRuleServiceOutGameDropItemBuilderInventoryGenerationRandomContext
约束:
CombatNode域不直接持有或复制组件产出规则。CombatScheduler与结算状态链只调用统一入口,不直接访问掉落池滚动或组件实例构造细节。InventoryGenerationComponent负责运行时入口、稳定临时实例 Id、Tag 随机上下文以及runSeed/sequenceIndex相关上下文。- 掉落是否产出组件由
OutGameDropRuleService决定;掉落池行到组件实例的构造由OutGameDropItemBuilder决定。
4.5.x InventoryGenerationRandomContext
文件:Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/InventoryGenerationRandomContext.cs
目标职责:
- 统一承载组件产出链路的随机合同。
- 统一派生:
- 商店 / 掉落 / 奖励候选的稳定随机流
- 稳定临时组件
InstanceId InventoryTagRandomContext
约束:
ShopGoodsBuilder、DropPoolRoller、RewardCandidateBuilder不再直接使用全局UnityEngine.Random。- 同一
runSeed + sequenceIndex + sourceType + localOrdinal下,应得到一致的物品本体与 Tag 结果。
4.6 CombatSettlementCalculator
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatSettlementCalculator.cs
目标职责:
- 只负责结算计算与
CombatSettlementContext组装。 - 负责基地血量奖励、奖励选择准入、奖励背包快照与耐久扣减目标计算。
约束:
- 不直接并包到玩家库存。
- 不直接打开 UI。
- 不承担奖励候选生成。
4.7 CombatSettlementCommitter
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatSettlementCommitter.cs
目标职责:
- 只负责把结算结果提交到玩家库存。
- 负责结算背包并包与延迟耐久扣减落地。
约束:
- 不重新计算结算上下文。
- 不直接生成奖励候选或打开 UI。
4.8 IPhaseEndCondition
目标职责:
- 作为
PhaseEndType判定接口。 - 每种
PhaseEndType对应一个实现类。
只读输入:
- 当前
DRLevelPhase - phase 时间信息
AliveEnemyCountIsPhaseSpawnCompletedHasAliveBoss
输出:
bool ShouldExit
约束:
- 不直接切状态。
- 不直接发事件。
- 不直接改资源。
5. EnemyManager 子服务边界
5.1 EnemySpawnDirector
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemySpawnDirector.cs
职责:
- 长期保留为独立服务。
- 基于
spawnEntries + phase time计算当前应执行的刷怪行为。 - 提供“当前 phase 的
SpawnEntry是否已全部执行完”的事实。
生命周期:
- 由
CombatRunningPhaseState在状态进入/退出时初始化与重置。
5.2 EnemySpawnPathResolver
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemySpawnPathResolver.cs
职责:
- 缓存当前地图可用
Spawner。 - 提供出生点与路径解析。
5.3 EnemyLifecycleTracker
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemyLifecycleTracker.cs
职责:
- 维护
AliveEnemyCount真值。 - 维护
HasAliveBoss真值。 - 追踪本局 tracked 敌人。
- 导出 tracked ids 供清场使用。
Boss 识别规则:
- Boss 身份由
DRLevelSpawnEntry.EntryType == Boss决定。 - 不由
DREnemy自身类型决定。
5.4 EnemyConfigProvider
文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemyConfigProvider.cs
职责:
- 读取
DREnemy。 - 处理默认配置兜底。
- 计算循环周目下的基础血量倍率。
6. 事件与数据流规范
6.1 MapEntity 与 Combat 域解耦
必须保持:
MapEntity不直接查询CombatNodeComponent的运行时资源字段。- 战斗初始上下文通过
MapData注入。 Coin初值通过MapData传入。- 后续
Coin变化通过CombatCoinChangedEventArgs同步。 TowerStatsData等本局不变量直接放进MapData。MapEntity不反查 Combat 域内部服务。
MapData 组装规则:
- 由
CombatLoadingState从局内资源管理器读取快照。 - 由
CombatLoadingState打包成MapData后再ShowEntity(MapEntity)。
6.2 敌人事件处理
统一边界:
EnemyManager只上报:OnEnemyDefeated(DREnemy enemy)OnEnemyReachedBase(DREnemy enemy)
CombatScheduler公共层负责处理敌人事件的通用副作用:- 击杀:调用
GameEntry.InventoryGeneration.ResolveEnemyDrop(...),再调用局内资源管理器入账。 - 到家:调用局内资源管理器扣减
BaseHp。
- 击杀:调用
约束:
- 敌人事件入口不直接调用
ChangeState(...)。 BaseHp <= 0的判断由当前状态在OnUpdate中处理。
6.3 战斗流程事件
发布边界:
- 资源变化事件由局内资源管理器发布。
- 流程/阶段事件由状态机或具体状态发布。
发布时间:
NodeEnterEventArgs:Loading完成并正式进入首个RunningPhase时。CombatProcessEventArgs:新 phase 的RunningPhase.OnEnter。CombatEnemyHpRateChangedEventArgs:与CombatProcessEventArgs同时发布。NodeCompleteEventArgs:WaitingForReturn完成清理、整场战斗真正退出时。
7. 结束链与结算上下文
7.1 统一结束链
正常结束统一走:
SettlementRewardSelection(可选)FinishFormWaitingForReturn
7.2 结算上下文
归属:
- 作为
CombatScheduler上的共享字段存在。 Settlement在OnEnter时统一构造。RewardSelection只追加奖励结果。FinishForm与WaitingForReturn只读取。
最小字段集合:
- 最终结算的
Gold/Coin结果 - 待合并的背包快照
BaseHp结算结果- 是否进入过奖励选择
FinishForm所需摘要数据
命名约束:
- 结算上下文中的布尔控制项统一收口到
Flags,不再使用Flow命名。
奖励选择约束:
- 满血奖励选择结果只写入结算上下文。
- 不直接写入局内资源管理器。
- 最终由结束状态链统一合并到玩家背包。
8. 核心不变量(必须保持)
CombatScheduler只做状态机管理与共享运行时收口,不继续吸收具体业务细节。CombatNodeComponent不再持有战斗内资源真值。- 局内
Coin / Gold / BaseHp / Loot Backpack / BuildTowerSnapshots以CombatRunResourceStore为唯一真值来源。 - 组件产出规则以
InventoryGenerationComponent为统一运行时入口;战斗掉落与奖励候选都通过它生成。 - 存活敌人数与
HasAliveBoss以EnemyLifecycleTracker为唯一真值来源。 - Phase 运行时信息与统一结束标记以
PhaseLoopRuntime为唯一真值来源。 PhaseEndType的退出条件以IPhaseEndCondition实现类为唯一判定入口。- 状态切换只能通过
CombatScheduler.ChangeState(...)完成。 - 敌人事件处理入口不直接切状态,状态只能在自己的
OnUpdate中决定迁移。 MapEntity通过MapData + Event获取战斗上下文,不反查 Combat 域内部运行时。
9. 清理职责
- 敌人清理:
EnemyManager,且只清理本局 tracked 敌人。 - 地图与战斗基础 UI 清理:
CombatLoadSession。 - 结算/奖励 UI 清理:结束状态链或
Failed状态。 - 运行时数据重置:
CombatScheduler在状态机生命周期边界统一执行。
10. 扩展开发规范
10.1 新增刷怪类型或 SpawnEntry 行为
优先改 EnemySpawnDirector,不要把时序细节塞进 CombatRunningPhaseState。
10.2 新增 Phase 结束条件
新增 IPhaseEndCondition 实现类,不要在 CombatWaitingForPhaseEndState 里写大分支。
10.3 新增敌人掉落规则
优先改 InventoryGenerationComponent 及其下层规则模块,不要在 EnemyManager、CombatScheduler 或状态类里直接计算掉落。
10.3.x 新增奖励候选规则
优先改 InventoryGenerationComponent、RewardCandidateBuilder 或 DropPoolRoller,不要在结算状态链里复制一套候选生成规则。
10.4 新增战斗内资源或建塔快照规则
优先改 CombatRunResourceStore,不要回流到 CombatNodeComponent。
10.5 新增地图/战斗基础 UI 加载规则
优先改 CombatLoadSession 或 CombatLoadingState,不要把加载细节塞回 CombatScheduler 本体。
10.6 新增强化结算、奖励选择、结算 UI 逻辑
优先改结束状态链:
CombatSettlementStateCombatRewardSelectionStateCombatFinishFormStateCombatWaitingForReturnState
10.7 新增战斗流程事件
优先由具体状态或局内资源管理器发布,不要回流到 CombatNodeComponent。
11. 代码变更检查清单(PR 自检)
- 新逻辑是否落在正确的状态或服务,而不是继续堆进
CombatScheduler本体? CombatNodeComponent是否仍然保持为轻量入口 Facade?- 是否破坏了局内资源、掉落判定、phase runtime、phase end 判定的唯一真值来源?
- 敌人事件处理是否仍然只做公共副作用,而不直接切状态?
- 状态迁移是否仍然统一走
ChangeState(...)? MapEntity是否仍然只通过MapData + Event获取战斗上下文?- 清理是否仍按”敌人 / 地图基础 UI / 结算 UI / 运行时数据”分工执行?
12. Combat Economy(战斗经济)
Status: 新增段落 — GDD 一致性审查中发现 Coin 经济在实现中存在但未写入文档 最后更新: 2026-04-30
本段说明战斗域内双货币体系的完整设计依据。所有数值均来自数据表驱动,无需代码硬编码。
12.1 双货币架构概述
游戏使用两层货币,分属不同生命周期:
| 货币 | 生命周期 | 存储位置 | 描述 |
|---|---|---|---|
| Coin | 单次战斗内 | CombatRunResourceStore.CurrentCoin |
战斗内部经济,用于建塔/升级/拆除 |
| Gold | 整局运行 | PlayerInventoryComponent.Gold |
跨节点持久,用于商店购买、出售 |
设计意图: Coin 创造战斗内的即时决策张力(”我现在花 Coin 建塔还是留着防万一?”);Gold 创造跨节点的战略张力(”我是现在买还是等下一个商店?”)。两层经济分离,防止任一层的决策深度被稀释。
关键约束: Coin 不跨战斗持久,战斗结束时清零。战斗胜利后 GainedGold 入账,GainedCoin 不入账。
12.2 Coin(战斗内部货币)
12.2.1 来源
| 来源 | 字段 | 说明 |
|---|---|---|
| 关卡初始 Coin | DRLevel.StartCoin |
战斗开始时发放,来源于 CombatRunResourceStore.InitializeForCombat() |
| 敌人击杀奖励 | DREnemy.DropCoin |
每次击杀敌人时发放,来源于 CombatRunResourceStore.AddEnemyDefeatedReward() |
StartCoin 按关卡难度配置,确保玩家在战斗开始时有足够的决策空间。建议低难度关卡 StartCoin 较低,高难度/Boss 关卡较高。
DropCoin 按敌人类型配置。建议普通敌人 DropCoin 较低(5–15),精英敌人较高(20–50),与 DropGold 分开计算。
12.2.2 消耗(Sinks)
| 操作 | 消耗方式 | 触发时机 |
|---|---|---|
| BuildTower | TryConsumeCoin(buildTowerCost[i]) |
玩家在战斗内点击建塔位,每槽位独立计费 |
| UpgradeTower | TryConsumeCoin(upgradeCost) |
玩家升级已有塔 |
| DestroyTower | 无消耗;返回 destroyGain Coin |
玩家拆除已有塔,Coin 返还 |
建塔槽位共 4 个(对应 BuildOptionCount = 4),每个槽位可独立消耗 Coin。每槽位的 buildTowerCost[i] 由关卡或战斗阶段配置。
12.2.3 追踪
CombatRunResourceStore.GainedCoin 记录本场战斗累计获得的 Coin。战斗结束时 GainedCoin 计入 RunStats.coinsEarned(跨战斗累计),但 Coin 本身不清零重置于下一个战斗,而是每个新战斗重新从 DRLevel.StartCoin 开始。
// 每场新战斗开始时
CurrentCoin = DRLevel.StartCoin // 从关卡配置重置,非累加
GainedCoin = 0 // 重置,用于本场统计
12.2.4 数据驱动约束
| 约束 | 值 | 说明 |
|---|---|---|
DRLevel.StartCoin |
≥ 0 | 建议普通关卡 50–200,Boss 关卡 100–300 |
DREnemy.DropCoin |
≥ 0 | 建议普通敌人 5–15,精英 20–50,Boss 0(避免重复计费) |
buildTowerCost[i] |
≥ 0 | 由 CombatSelectFormUseCase 从关卡配置读取,建议 20–80 每槽位 |
upgradeCost |
≥ 0 | 由 CombatSelectFormUseCase 从关卡配置读取,建议 50–150 |
destroyGain |
≥ 0 | 建议 = buildTowerCost * 0.5(返还 50%),与商店售价机制一致 |
12.3 Gold(战斗内获取部分)
战斗过程中 Gold 获取有两个来源:
12.3.1 敌人击杀掉落
// DREnemy 字段
DropGold // 掉落金币数额
DropPercent // 掉落概率 [0.0, 1.0]
战斗胜利时(敌人被击杀或波次结束),若随机值 ≤ DropPercent,则 AddEnemyDefeatedReward(gainedCoin, gainedGold) 被调用,gainedGold = DropGold。
12.3.2 关卡胜利奖励
战斗胜利结算时(CombatSettlementState),CombatSettlementCalculator 计算本场战斗总 Gold 奖励:DRLevel.RewardGold,通过 CombatRunResourceStore.AddSettlementGold() 入账。
战斗失败时:无 RewardGold,GainedGold = 0。
12.3.3 追踪
CombatRunResourceStore.GainedGold 记录本场战斗累计获得的 Gold(击杀掉落 + 胜利奖励)。战斗结束时通过 GetRewardInventorySnapshot() 合并至玩家主背包(PlayerInventoryComponent.MergeInventory()),触发 MaxPlayerGold = 9999 上限检查(溢出部分丢弃)。
12.4 Coin 与 Gold 的运行时边界
战斗开始 → InitializeForCombat(level)
└→ CurrentCoin = level.StartCoin // Coin 重置
└→ GainedCoin = 0, GainedGold = 0 // 本场统计重置
战斗过程中(敌人死亡)→ AddEnemyDefeatedReward(dropCoin, dropGold)
└→ CurrentCoin += dropCoin
└→ CurrentGold (奖励库存) += dropGold // 不影响主背包
└→ GainedCoin += dropCoin
└→ GainedGold += dropGold
战斗胜利 → AddSettlementGold(RewardGold)
└→ GainedGold += RewardGold
战斗结束 → GetRewardInventorySnapshot() → MergeInventory()
└→ 主背包 Gold += min(rewardGold, MaxPlayerGold - currentGold)
└→ 主背包组件 += 奖励组件
└→ RunStats.coinsEarned += GainedCoin // 仅统计,不持久化 Coin
12.5 Progression 的 coinEarned 字段
| 字段 | 类型 | 说明 |
|---|---|---|
RunStats.coinsEarned |
int | 跨战斗累计:本 run 所有战斗累计获得的 Coin 总和(战斗失败也计入) |
coinsEarned 用于统计目的,不产生任何游戏内效果。它记录玩家在一局 run 中总共获得了多少 Coin — 可用于未来功能(如”累计获得 10000 Coin”成就),但当前无对应解锁或奖励。
12.6 与商店经济的隔离
Coin 仅在战斗域内流通。商店系统(design/gdd/shop.md)处理的 buy/sell 交易仅涉及 Gold,不涉及 Coin。
- 战斗内不会触发商店交易
- 商店内不会消耗或获得 Coin
- 战斗结束时,Coin 不转换为 Gold(
GainedCoin仅计入RunStats,不进入玩家背包)
12.7 调试与一致性检查
| 检查项 | 预期结果 |
|---|---|
新战斗开始时 CurrentCoin == DRLevel.StartCoin |
相等 |
战斗结束时 GainedCoin ≥ 0 |
大于等于零 |
战斗失败时 GainedGold == 0 |
战斗失败不发放 Gold 奖励 |
MaxPlayerGold 上限检查 |
MergeInventory 后背包 Gold ≤ 9999 |
Coin 消耗后 CurrentCoin ≥ 0 |
TryConsumeCoin 失败时 CurrentCoin 不变 |