补全 CombatNode 逻辑 + 重构 EnemyManager
- 添加了关卡内的难度系数与掉落
- 难度系数:每循环一轮波次敌人血量翻倍
- 道具掉落:按照掉落概率曲线根据波次计算当前爆率,并从新增的道具池里选择道具
- `CombatResourceManager`:统一维护关卡内资源状态(硬币/金币/道具掉落)
- 重构 `EnemyManager`:
- `EnemyManager`:编排子服务,不承载具体业务细节
- `EnemySpawnDirector`:管理刷怪时序
- `SpawnerResolver`:管理出生点与路径
- `EnemyLifecycleTracker`:追踪敌人生命周期
- `EnemyConfigService`:管理敌人配置与倍率
This commit is contained in:
+99
-193
@@ -1,221 +1,127 @@
|
||||
# CombatNode 架构摘要
|
||||
# CombatNode Architecture
|
||||
|
||||
最后更新:2026-02-28
|
||||
最后更新:2026-03-02
|
||||
|
||||
## 1. 目标与边界
|
||||
## 1. 总览
|
||||
CombatNode 当前分为三层:
|
||||
- `CombatNodeComponent`:入口与关卡数据装配。
|
||||
- `CombatScheduler`:战斗状态机与阶段推进,以及关卡内资源结算。
|
||||
- `EnemyManager`:敌人系统 Facade(对外接口保持稳定,内部由多个子服务协作)。
|
||||
|
||||
CombatNode 子系统的目标是把“战斗节点”拆成三个稳定层:
|
||||
本文重点记录 `EnemyManager` 与 `CombatScheduler` 的职责边界(尤其资源管理收口后的模型)。
|
||||
|
||||
- `CombatNodeComponent`:节点入口与配置缓存(门面层)
|
||||
- `CombatScheduler`:单局战斗状态机(编排层)
|
||||
- `EnemyManager`:刷怪与敌人生命周期(执行层)
|
||||
## 2. EnemyManager 相关类
|
||||
|
||||
边界约束:
|
||||
|
||||
- 只负责战斗节点,不负责菜单流程切换,不负责 UI 细节。
|
||||
- 只依赖数据表和 Entity 系统,不直接持有场景流程 FSM。
|
||||
- 地图寻路由 `MapEntity` 提供能力,敌人移动由 `EnemyEntity` 自治。
|
||||
|
||||
---
|
||||
|
||||
## 2. 模块职责划分
|
||||
|
||||
## 2.1 CombatNodeComponent(门面层)
|
||||
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs`
|
||||
### 2.1 EnemyManager(Facade)
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemyManager.cs`
|
||||
|
||||
职责:
|
||||
- 对 `CombatScheduler` 提供统一接口:`OnInit / BeginPhase / OnUpdate / EndPhase / OnDestroy`。
|
||||
- 编排敌人域子服务,不承载具体业务细节。
|
||||
- 转发状态:`AliveEnemyCount`、`IsPhaseRunning`、`IsPhaseSpawnCompleted`。
|
||||
- 处理敌人实体事件(Show/Hide)后的结果上报:
|
||||
- 击杀:上报 `coin/gold` 到 `CombatScheduler.OnEnemyDefeatedRewardResolved(...)`
|
||||
- 到家:上报 `baseDamage` 到 `CombatScheduler.OnEnemyReachedBase(...)`
|
||||
|
||||
- 读取并缓存 `DRLevel / DRLevelPhase / DRLevelSpawnEntry`。
|
||||
- 按主题筛选关卡,维护 `Level -> Phase -> SpawnEntry` 映射。
|
||||
- 提供 `OnInit / StartCombat / OnUpdate / OnShutdown` 外部接口。
|
||||
- 触发节点事件:
|
||||
- `NodeEnterEventArgs`
|
||||
- `NodeCompleteEventArgs`
|
||||
不负责:
|
||||
- 不直接维护刷怪时间轴。
|
||||
- 不直接维护出生点缓存与路径查询。
|
||||
- 不直接维护敌人追踪结构。
|
||||
- 不直接维护掉落池抽样与背包库存。
|
||||
- 不直接维护敌人配置兜底和血量倍率算法。
|
||||
|
||||
不做的事:
|
||||
|
||||
- 不做阶段推进。
|
||||
- 不做刷怪时序。
|
||||
- 不做实体显示/隐藏细节。
|
||||
|
||||
## 2.2 CombatScheduler(编排层)
|
||||
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler.cs`
|
||||
### 2.2 EnemySpawnDirector(刷怪时序)
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemySpawnDirector.cs`
|
||||
|
||||
职责:
|
||||
- 管理 `DRLevelSpawnEntry` 的运行时实例(`SpawnEntryRuntime`)。
|
||||
- 按时间推进 `Stream / Burst / Boss` 生成逻辑。
|
||||
- 输出“当前应生成多少敌人”,通过回调交给 `EnemyManager.SpawnEnemies` 执行。
|
||||
- 维护阶段刷怪状态:`IsPhaseRunning`、`IsPhaseSpawnCompleted`。
|
||||
|
||||
- 管理战斗状态机:`Idle -> WaitingForMap -> RunningPhase -> Completed/Failed`。
|
||||
- 加载地图实体,接收地图 show/hide 成功失败事件。
|
||||
- 按 phase 结束条件推进到下一阶段。
|
||||
- 在开始新战斗或销毁时做统一清场(地图 + 本局敌人)。
|
||||
|
||||
不做的事:
|
||||
|
||||
- 不直接计算每条刷怪规则的触发细节(交给 `EnemyManager`)。
|
||||
|
||||
## 2.3 EnemyManager(执行层)
|
||||
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager.cs`
|
||||
### 2.3 SpawnerResolver(出生点与路径)
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/SpawnerResolver.cs`
|
||||
|
||||
职责:
|
||||
- 缓存当前地图可用 `Spawner`。
|
||||
- 支持 `SpawnOrder` 映射与 fallback 轮询。
|
||||
- 对外提供 `TryResolveSpawnPath(...)`,返回世界坐标路径点。
|
||||
- 在地图切换时刷新缓存,避免每次刷怪全量扫描。
|
||||
|
||||
- 将 `DRLevelSpawnEntry` 转为运行时任务(stream/burst/boss)。
|
||||
- 按时间推进刷怪任务并生成 `EnemyData`。
|
||||
- 维护本局敌人数量 `AliveEnemyCount`。
|
||||
- 维护“本局生成敌人 ID 集合”,用于准确计数与清场。
|
||||
|
||||
关键点:
|
||||
|
||||
- 生命周期归属按 `entityId` 跟踪,不再按实体组名粗粒度统计。
|
||||
- 清场可覆盖“已加载 + 加载中”的本局敌人。
|
||||
|
||||
---
|
||||
|
||||
## 3. 关键实体职责
|
||||
|
||||
## 3.1 MapEntity
|
||||
|
||||
文件:`Assets/GameMain/Scripts/Entity/EntityLogic/MapEntity.cs`
|
||||
### 2.4 EnemyLifecycleTracker(敌人生命周期追踪)
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemyLifecycleTracker.cs`
|
||||
|
||||
职责:
|
||||
- 追踪本局敌人 `entityId -> DREnemy`。
|
||||
- 维护 `AliveEnemyCount`。
|
||||
- 处理 `ShowSuccess / ShowFailure / HideComplete` 对追踪状态的变更。
|
||||
- 提供批量导出 tracked ids,用于 `CleanupTrackedEnemies` 清场。
|
||||
|
||||
- 读取 Tilemap,识别 Path/Foundation 格子。
|
||||
- 为每个 `Spawner` 缓存默认可达路径。
|
||||
- 提供:
|
||||
- `TryGetDefaultPathCells`
|
||||
- `TryFindPathCells`
|
||||
- `TryFindPathWorldPoints`
|
||||
|
||||
## 3.2 EnemyEntity
|
||||
|
||||
文件:`Assets/GameMain/Scripts/Entity/EntityLogic/EnemyEntity.cs`
|
||||
### 2.5 EnemyConfigService(敌人配置与倍率)
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemyConfigService.cs`
|
||||
|
||||
职责:
|
||||
- 读取 `DREnemy`,处理默认配置兜底。
|
||||
- 计算循环周目下的基础血量倍率(按 `displayPhaseIndex / phaseCount` 推导 loop)。
|
||||
- 缓存数据表引用并在 `Reset` 时清理。
|
||||
|
||||
- 按路径点移动。
|
||||
- 到达终点后调用 `HideEntity` 自行退出。
|
||||
## 3. CombatScheduler 资源收口
|
||||
|
||||
---
|
||||
### 3.1 CombatResourceManager(关卡内资源统一管理)
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatResourceManager.cs`
|
||||
|
||||
## 4. 运行时时序(简版)
|
||||
职责:
|
||||
- 统一维护关卡内资源状态:
|
||||
- `GainedCoin`、`GainedGold`
|
||||
- `BackpackInventoryData`(结算背包快照)
|
||||
- 处理击杀奖励入账:`AddEnemyDefeatedReward(...)`
|
||||
- 处理局外掉落抽样与物品构建:`TryRollOutGameItemDrop(...)`
|
||||
- 对结算 UI 提供只读快照:`GetRewardInventorySnapshot()`
|
||||
|
||||
1. 菜单触发战斗:`TestMenuFormController -> GameEntry.CombatNode.StartCombat()`
|
||||
2. `CombatNodeComponent.StartCombat()` 选关并把关卡配置交给 `CombatScheduler.Start()`
|
||||
3. `CombatScheduler.Start()` 先清理上局残留,再 `ShowMap(...)`,状态进入 `WaitingForMap`
|
||||
4. 地图加载成功事件到达,`_currentMap` 就绪
|
||||
5. `BeginNextPhase()` 进入 `RunningPhase`,`EnemyManager.BeginPhase(...)`
|
||||
6. 每帧 `OnUpdate`:
|
||||
- `CombatScheduler` 更新时间与结束条件
|
||||
- `EnemyManager` 推进刷怪任务并创建敌人
|
||||
7. 当前 phase 满足结束条件,`CompleteCurrentPhase()`,然后进入下一 phase
|
||||
8. 全 phase 完成后隐藏地图,`GameEntry.CombatNode.EndCombat()`,抛 `NodeComplete`
|
||||
### 3.2 CombatScheduler 与资源类关系
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatScheduler.cs`
|
||||
|
||||
---
|
||||
当前模型:
|
||||
- `CombatScheduler` 持有 `_combatResourceManager`。
|
||||
- `GainedCoin/GainedGold` 属性透传资源类。
|
||||
- `OnEnemyDefeatedRewardResolved(...)` 统一触发:
|
||||
- 货币入账
|
||||
- 关卡内掉落判定
|
||||
- `EnterFinishFlow(...)` 从资源类取 `BackpackInventoryData` 作为结算数据。
|
||||
|
||||
## 5. 数据契约与 ID 规则
|
||||
## 4. 协作流程(简版)
|
||||
1. `CombatScheduler.BeginNextPhase()` 调 `EnemyManager.BeginPhase(...)`。
|
||||
2. `EnemyManager` 刷新 `SpawnerResolver` 缓存,并通知 `EnemySpawnDirector.BeginPhase(...)`。
|
||||
3. 每帧 `EnemyManager.OnUpdate(...)`:
|
||||
- `SpawnerResolver.RefreshCache(...)`
|
||||
- `EnemySpawnDirector.OnUpdate(..., SpawnEnemies)`
|
||||
4. `SpawnEnemies(...)` 执行实际生成:
|
||||
- `SpawnerResolver.TryResolveSpawnPath(...)`
|
||||
- `EnemyConfigService.GetEnemyConfig(...)`
|
||||
- `EnemyConfigService.ResolveScaledEnemyBaseHp(...)`
|
||||
- `EnemyLifecycleTracker.TrackEnemy(...)`
|
||||
- `GameEntry.Entity.ShowEnemy(...)`
|
||||
5. 敌人回收时 `EnemyManager.OnHideEntityComplete(...)`:
|
||||
- `EnemyLifecycleTracker.TryHandleHideComplete(...)`
|
||||
- 若击杀:上报 `coin/gold` 给 `CombatScheduler.OnEnemyDefeatedRewardResolved(...)`
|
||||
- 若到家:上报 `baseDamage` 给 `CombatScheduler.OnEnemyReachedBase(...)`
|
||||
6. `CombatScheduler.OnEnemyDefeatedRewardResolved(...)`:
|
||||
- `CombatResourceManager.AddEnemyDefeatedReward(...)`
|
||||
- `CombatResourceManager.TryRollOutGameItemDrop(...)`
|
||||
7. `CombatScheduler.EnterFinishFlow(...)`:
|
||||
- 读取 `CombatResourceManager.GetRewardInventorySnapshot()`
|
||||
- 打开结算 UI
|
||||
|
||||
数据来源:
|
||||
## 5. 关键不变量
|
||||
- 存活敌人数以 `EnemyLifecycleTracker.AliveEnemyCount` 为唯一真值来源。
|
||||
- 刷怪阶段状态以 `EnemySpawnDirector` 为唯一真值来源。
|
||||
- 关卡内资源以 `CombatResourceManager` 为唯一真值来源。
|
||||
- `EnemyManager` 只做敌人域编排与结果上报,不再持有奖励库存。
|
||||
- 清场必须只作用于本局 tracked 敌人,避免误伤其他实体。
|
||||
|
||||
- `DRLevel`
|
||||
- `DRLevelPhase`
|
||||
- `DRLevelSpawnEntry`
|
||||
|
||||
当前约定(依赖 ID 编码):
|
||||
|
||||
- `levelId = phaseId / 1000`
|
||||
- `phaseId = spawnEntryId / 1000`
|
||||
|
||||
影响:
|
||||
|
||||
- 新增配置时必须遵守该编码,否则 phase 和 entry 无法被正确归属。
|
||||
|
||||
建议:
|
||||
|
||||
- 若后续改数据结构,优先改成显式外键字段,减少 ID 推导耦合。
|
||||
|
||||
---
|
||||
|
||||
## 6. 结束条件模型
|
||||
|
||||
枚举:`PhaseEndType`
|
||||
|
||||
- `TimeElapsed`:按 `EndParam`(可解析 float)或 `DurationSeconds`
|
||||
- `EnemiesCleared`:`IsPhaseSpawnCompleted && AliveEnemyCount <= 0`
|
||||
- `BossDead`:当前与 `EnemiesCleared` 同判定
|
||||
- `None`:有 duration 走 duration,否则退化为清怪判定
|
||||
|
||||
实现点:`CombatScheduler.ShouldEndCurrentPhase()`
|
||||
|
||||
---
|
||||
|
||||
## 7. 生命周期与清场策略(当前实现)
|
||||
|
||||
## 7.1 地图生命周期
|
||||
|
||||
- 通过 `ShowMap` 异步加载。
|
||||
- 通过 `ShowEntitySuccess/Failure` 绑定运行态地图引用。
|
||||
- 完成关卡时隐藏地图。
|
||||
- 新战斗开始和调度器销毁前都会尝试清理地图实体。
|
||||
|
||||
## 7.2 敌人生命周期
|
||||
|
||||
- 创建时登记 `entityId` 到 `_trackedEnemyEntityIds`。
|
||||
- `ShowEntitySuccess` 仅对 tracked id 计数。
|
||||
- `HideEntityComplete` 仅对 tracked id 减计数并移除跟踪。
|
||||
- 清场时按 tracked id 隐藏(覆盖加载中和已加载实体)。
|
||||
|
||||
## 7.3 设计目标
|
||||
|
||||
- 防止跨局残留实体污染新局状态。
|
||||
- 防止其他系统 `Enemy` 组实体干扰战斗计数。
|
||||
|
||||
---
|
||||
|
||||
## 8. 扩展指南(按需求)
|
||||
|
||||
## 8.1 新增阶段结束条件
|
||||
|
||||
- 改 `PhaseEndType` 枚举。
|
||||
- 在 `ShouldEndCurrentPhase()` 增加分支。
|
||||
|
||||
## 8.2 新增刷怪条目类型
|
||||
|
||||
- 改 `EntryType` 枚举。
|
||||
- 在 `EnemyManager.BuildSpawnRuntime()` 与 `UpdateSpawnRuntimes()` 增加处理。
|
||||
|
||||
## 8.3 改选关策略
|
||||
|
||||
- 当前是随机选关:`TrySelectRandomLevel()`。
|
||||
- 可改为按难度、解锁进度、权重池。
|
||||
|
||||
## 8.4 动态阻挡/重算路径
|
||||
|
||||
- 当前 `SpawnEnemies` 调 `TryFindPathWorldPoints(spawner, null, ...)`。
|
||||
- 若支持塔阻挡,传入 `blockedCells` 并处理“无路可走”策略。
|
||||
|
||||
## 8.5 结算与奖励
|
||||
|
||||
- 推荐挂在 `CombatScheduler` 完成分支(所有 phase 完成处),不要塞进 `EnemyManager`。
|
||||
|
||||
---
|
||||
|
||||
## 9. 维护时的硬性不变量
|
||||
|
||||
- `CombatNodeComponent` 只做缓存和入口,不写战斗细节。
|
||||
- `CombatScheduler` 是唯一 phase 状态机,不在别处推进 phase。
|
||||
- `AliveEnemyCount` 必须由 tracked id 驱动,不回退到组名统计。
|
||||
- 新战斗开始前必须清场。
|
||||
- `ResetRuntime()` 必须清空地图相关运行态引用和 id。
|
||||
|
||||
---
|
||||
|
||||
## 10. 快速阅读路径(新人 10 分钟)
|
||||
|
||||
1. `CombatNodeComponent.StartCombat()`
|
||||
2. `CombatScheduler.Start() / OnUpdate() / BeginNextPhase()`
|
||||
3. `EnemyManager.BeginPhase() / OnUpdate() / SpawnEnemies()`
|
||||
4. `MapEntity.TryFindPathWorldPoints()`
|
||||
5. `EnemyEntity.DespawnOnReachHouse()`
|
||||
|
||||
这 5 个点读完,基本能覆盖 90% 战斗节点行为。
|
||||
## 6. 维护建议
|
||||
- 新增刷怪类型:优先改 `EnemySpawnDirector`。
|
||||
- 新增路径/出生规则:优先改 `SpawnerResolver`。
|
||||
- 新增敌人追踪策略:优先改 `EnemyLifecycleTracker`。
|
||||
- 新增敌人配置兜底或倍率策略:优先改 `EnemyConfigService`。
|
||||
- 新增货币/掉落/结算背包规则:优先改 `CombatResourceManager`。
|
||||
|
||||
Reference in New Issue
Block a user