geometry-tower-defense/docs/CombatNodeArchitecture.md

16 KiB
Raw Blame History

CombatNode 设计规范(开发约束)

最后更新2026-03-06

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
  • 对外暴露只读运行时属性。
  • 提供少量用户入口,例如 StartCombatTryEndCombatByPlayer

长期不负责:

  • 不直接持有 Coin / Gold / BaseHp / Loot Backpack 的真值。
  • 不直接缓存本局建塔属性快照。
  • 不直接发布战斗流程事件。
  • 不直接处理敌人掉落、结算、奖励选择、地图加载。

2.2 CombatScheduler状态机管理器

文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatScheduler.cs

长期职责:

  • 持有共享运行时数据与共享服务实例。
  • 管理状态实例。
  • 提供统一的 ChangeState(...) 状态迁移入口。
  • 提供敌人事件的公共处理入口。
  • 作为状态机生命周期边界,统一做运行时重置。

长期不负责:

  • 不直接硬编码加载流程。
  • 不直接硬编码结算流程。
  • 不直接硬编码奖励选择 UI 逻辑。
  • 不直接硬编码 PhaseEndType 结束条件。

推荐状态类命名:

  • CombatLoadingState
  • CombatRunningPhaseState
  • CombatWaitingForPhaseEndState
  • CombatSettlementState
  • CombatRewardSelectionState
  • CombatFinishFormState
  • CombatWaitingForReturnState
  • CombatFailedState

实现约束:

  • 上述状态类作为 CombatScheduler 的嵌套类实现。
  • 共享数据与共享服务统一放在 CombatScheduler 上。
  • 所有状态切换只能通过 CombatScheduler.ChangeState(...) 完成。
  • 状态类不能彼此直接操控。

2.3 EnemyManager敌人域 Facade

文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemyManager.cs

长期职责:

  • 对状态机提供统一敌人域接口。
  • 编排敌人子服务。
  • 暴露只读事实:
    • AliveEnemyCount
    • IsPhaseSpawnCompleted
    • HasAliveBoss
  • 在敌人死亡或到家时,通过公共入口向 CombatScheduler 上报:
    • OnEnemyDefeated(DREnemy enemy)
    • OnEnemyReachedBase(DREnemy enemy)

长期不负责:

  • 不直接给资源入账。
  • 不直接扣基地血量。
  • 不直接决定状态切换。

3. 状态机模型

3.1 状态列表(目标)

  • Loading
  • RunningPhase
  • WaitingForPhaseEnd
  • Settlement
  • RewardSelection
  • FinishForm
  • WaitingForReturn
  • Failed

说明:

  • 正常结束流只有一条状态链:
    • Settlement -> RewardSelection(可选) -> FinishForm -> WaitingForReturn
  • 正常通关、玩家主动结束、基地血量归零都走同一条结束链。
  • Failed 仅用于异常失败,不用于“基地被击破”这类正常战斗失败。

3.2 CombatLoadingState

职责:

  • 通过 CombatLoadSession 执行地图与基础战斗 UI 加载。
  • 从局内资源管理器读取本局快照。
  • 组装 MapData 并发起 ShowEntity(MapEntity)

约束:

  • 只负责加载,不负责初始化局内资源。
  • 局内资源必须在进入状态机前初始化完成。

3.3 CombatRunningPhaseState

职责:

  • 执行当前 DRLevelPhase 的行为。
  • 推进 SpawnEntry 时序与出怪。
  • 管理 EnemySpawnDirector 的阶段级初始化与重置。
  • 在新 phase 开始时发布:
    • CombatProcessEventArgs
    • CombatEnemyHpRateChangedEventArgs

退出条件:

  • 当前 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 CombatLoadSession

文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatLoadSession.cs

长期定位:

  • 长期保留的独立加载服务。
  • 专门负责地图与战斗内基础 UI 的加载/清理。

职责:

  • 加载地图实体。
  • 打开/关闭 CombatInfoForm
  • 跟踪加载成功/失败状态。
  • 对外提供 CurrentMapIsReady

4.2 PhaseLoopRuntime

文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/PhaseLoopRuntime.cs

长期定位:

  • 长期保留的独立 phase runtime 服务。

职责:

  • 维护当前 DRLevelPhase
  • 维护 DisplayPhaseIndexPhaseCount
  • 维护统一的 phase 时间基准,例如 phaseElapsedTimephaseStartTime
  • 负责进入下一 phase。
  • 持有统一“请求结束战斗”标记。

约束:

  • 只做 phase 运行时数据管理,不直接切状态。

4.3 CombatInRunResourceManager推荐命名

当前相关文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatResourceManager.cs

目标职责:

  • 持有本局 Coin 真值。
  • 持有本局累计 Gold 真值。
  • 持有本局 BaseHp 真值。
  • 持有本局战利品背包。
  • 持有本局建塔属性快照。
  • 提供只读快照给结束状态链与加载状态使用。
  • 发布资源变化事件:
    • CombatCoinChangedEventArgs
    • CombatBaseHpChangedEventArgs

初始化约束:

  • 在进入状态机前完成初始化。
  • 由内部从 PlayerInventory 获取并缓存本局建塔快照。

事件约束:

  • Coin / BaseHp 变化事件同时携带“当前值”和“变化量”。
  • Gold 只是结算累计值,不要求战斗内实时事件驱动。

4.4 EnemyDropResolver推荐命名

当前相关文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatResourceManager.cs

目标职责:

  • 只负责敌人死亡后的掉落判定。
  • 输入:
    • DREnemy
    • 当前阶段索引
    • 当前主题或关卡上下文
  • 输出:
    • 掉落结果对象(coin / gold / loot

约束:

  • 不直接修改资源状态。
  • 不直接读取 CombatNodeComponentMapEntityEnemyManager 内部状态。

4.5 IPhaseEndCondition推荐命名

目标职责:

  • 作为 PhaseEndType 判定接口。
  • 每种 PhaseEndType 对应一个实现类。

只读输入:

  • 当前 DRLevelPhase
  • phase 时间信息
  • AliveEnemyCount
  • IsPhaseSpawnCompleted
  • HasAliveBoss

输出:

  • bool ShouldExit

约束:

  • 不直接切状态。
  • 不直接发事件。
  • 不直接改资源。

5. EnemyManager 子服务边界

5.1 EnemySpawnDirector

文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemySpawnDirector.cs

职责:

  • 长期保留为独立服务。
  • 基于 spawnEntries + phase time 计算当前应执行的刷怪行为。
  • 提供“当前 phase 的 SpawnEntry 是否已全部执行完”的事实。

生命周期:

  • CombatRunningPhaseState 在状态进入/退出时初始化与重置。

5.2 SpawnerResolver

文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/SpawnerResolver.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 EnemyConfigService

文件:Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemyConfigService.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 公共层负责处理敌人事件的通用副作用:
    • 击杀:调用 EnemyDropResolver,再调用局内资源管理器入账。
    • 到家:调用局内资源管理器扣减 BaseHp

约束:

  • 敌人事件入口不直接调用 ChangeState(...)
  • BaseHp <= 0 的判断由当前状态在 OnUpdate 中处理。

6.3 战斗流程事件

发布边界:

  • 资源变化事件由局内资源管理器发布。
  • 流程/阶段事件由状态机或具体状态发布。

发布时间:

  • NodeEnterEventArgsLoading 完成并正式进入首个 RunningPhase 时。
  • CombatProcessEventArgs:新 phase 的 RunningPhase.OnEnter
  • CombatEnemyHpRateChangedEventArgs:与 CombatProcessEventArgs 同时发布。
  • NodeCompleteEventArgsWaitingForReturn 完成清理、整场战斗真正退出时。

7. 结束链与结算上下文

7.1 统一结束链

正常结束统一走:

  • Settlement
  • RewardSelection(可选)
  • FinishForm
  • WaitingForReturn

7.2 结算上下文

归属:

  • 作为 CombatScheduler 上的共享字段存在。
  • SettlementOnEnter 时统一构造。
  • RewardSelection 只追加奖励结果。
  • FinishFormWaitingForReturn 只读取。

最小字段集合:

  • 最终结算的 Gold/Coin 结果
  • 待合并的背包快照
  • BaseHp 结算结果
  • 是否进入过奖励选择
  • FinishForm 所需摘要数据

奖励选择约束:

  • 满血奖励选择结果只写入结算上下文。
  • 不直接写入局内资源管理器。
  • 最终由结束状态链统一合并到玩家背包。

8. 核心不变量(必须保持)

  1. CombatScheduler 只做状态机管理与共享运行时收口,不继续吸收具体业务细节。
  2. CombatNodeComponent 不再持有战斗内资源真值。
  3. 局内 Coin / Gold / BaseHp / Loot Backpack / BuildTowerSnapshotsCombatInRunResourceManager 为唯一真值来源。
  4. 敌人死亡掉落判定以 EnemyDropResolver 为唯一判定入口。
  5. 存活敌人数与 HasAliveBossEnemyLifecycleTracker 为唯一真值来源。
  6. Phase 运行时信息与统一结束标记以 PhaseLoopRuntime 为唯一真值来源。
  7. PhaseEndType 的退出条件以 IPhaseEndCondition 实现类为唯一判定入口。
  8. 状态切换只能通过 CombatScheduler.ChangeState(...) 完成。
  9. 敌人事件处理入口不直接切状态,状态只能在自己的 OnUpdate 中决定迁移。
  10. 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 新增敌人掉落规则

优先改 EnemyDropResolver,不要在 EnemyManager 或状态类里直接计算掉落。

10.4 新增战斗内资源或建塔快照规则

优先改 CombatInRunResourceManager,不要回流到 CombatNodeComponent

10.5 新增地图/战斗基础 UI 加载规则

优先改 CombatLoadSessionCombatLoadingState,不要把加载细节塞回 CombatScheduler 本体。

10.6 新增强化结算、奖励选择、结算 UI 逻辑

优先改结束状态链:

  • CombatSettlementState
  • CombatRewardSelectionState
  • CombatFinishFormState
  • CombatWaitingForReturnState

10.7 新增战斗流程事件

优先由具体状态或局内资源管理器发布,不要回流到 CombatNodeComponent


11. 代码变更检查清单PR 自检)

  1. 新逻辑是否落在正确的状态或服务,而不是继续堆进 CombatScheduler 本体?
  2. CombatNodeComponent 是否仍然保持为轻量入口 Facade
  3. 是否破坏了局内资源、掉落判定、phase runtime、phase end 判定的唯一真值来源?
  4. 敌人事件处理是否仍然只做公共副作用,而不直接切状态?
  5. 状态迁移是否仍然统一走 ChangeState(...)
  6. MapEntity 是否仍然只通过 MapData + Event 获取战斗上下文?
  7. 清理是否仍按“敌人 / 地图基础 UI / 结算 UI / 运行时数据”分工执行?