init
This commit is contained in:
@@ -0,0 +1,736 @@
|
||||
# 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` 结束条件。
|
||||
|
||||
推荐状态类命名:
|
||||
- `CombatLoadingState`
|
||||
- `CombatRunningPhaseState`
|
||||
- `CombatWaitingForPhaseEndState`
|
||||
- `CombatSettlementState`
|
||||
- `CombatRewardSelectionState`
|
||||
- `CombatFinishFormState`
|
||||
- `CombatWaitingForReturnState`
|
||||
- `CombatFailedState`
|
||||
|
||||
实现约束:
|
||||
- 上述状态类可以作为 `CombatScheduler` 的嵌套类实现,也可以拆成独立文件;但必须只服务于 `CombatScheduler` 状态机,不形成独立业务边界。
|
||||
- 共享数据与共享服务统一收口到 `CombatScheduler` 内部持有的运行时承载体,不允许散落在各状态类中。
|
||||
- 若 `CombatScheduler` 体量过大,允许在其内部实现中继续拆出:
|
||||
- `CombatSchedulerRuntime`:承载共享运行时字段与共享服务引用
|
||||
- `CombatSchedulerCoordinator`:承载多个状态共用的流程辅助方法
|
||||
- 上述拆分只属于 `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 命名后缀词典
|
||||
|
||||
- `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` 真值。
|
||||
- 持有本局战利品背包。
|
||||
- 持有本局建塔属性快照。
|
||||
- 提供只读快照给结束状态链与加载状态使用。
|
||||
- 发布资源变化事件:
|
||||
- `CombatCoinChangedEventArgs`
|
||||
- `CombatBaseHpChangedEventArgs`
|
||||
|
||||
初始化约束:
|
||||
- 在进入状态机前完成初始化。
|
||||
- 由内部从 `PlayerInventory` 获取并缓存本局建塔快照。
|
||||
|
||||
事件约束:
|
||||
- `Coin / BaseHp` 变化事件同时携带“当前值”和“变化量”。
|
||||
- `Gold` 只是结算累计值,不要求战斗内实时事件驱动。
|
||||
|
||||
### 4.5 InventoryGenerationComponent
|
||||
|
||||
文件:`Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/InventoryGenerationComponent.cs`
|
||||
|
||||
目标职责:
|
||||
- 作为局外组件产出的统一运行时入口。
|
||||
- 对外提供:
|
||||
- `BuildShopGoods(...)`
|
||||
- `ResolveEnemyDrop(...)`
|
||||
- `BuildRewardCandidates(...)`
|
||||
- 在内部编排:
|
||||
- `DropPoolRoller`
|
||||
- `RewardCandidateBuilder`
|
||||
- `OutGameDropRuleService`
|
||||
- `OutGameDropItemBuilder`
|
||||
- `InventoryGenerationRandomContext`
|
||||
|
||||
约束:
|
||||
- `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 时间信息
|
||||
- `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 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 统一结束链
|
||||
|
||||
正常结束统一走:
|
||||
- `Settlement`
|
||||
- `RewardSelection`(可选)
|
||||
- `FinishForm`
|
||||
- `WaitingForReturn`
|
||||
|
||||
### 7.2 结算上下文
|
||||
|
||||
归属:
|
||||
- 作为 `CombatScheduler` 上的共享字段存在。
|
||||
- `Settlement` 在 `OnEnter` 时统一构造。
|
||||
- `RewardSelection` 只追加奖励结果。
|
||||
- `FinishForm` 与 `WaitingForReturn` 只读取。
|
||||
|
||||
最小字段集合:
|
||||
- 最终结算的 `Gold/Coin` 结果
|
||||
- 待合并的背包快照
|
||||
- `BaseHp` 结算结果
|
||||
- 是否进入过奖励选择
|
||||
- `FinishForm` 所需摘要数据
|
||||
|
||||
命名约束:
|
||||
- 结算上下文中的布尔控制项统一收口到 `Flags`,不再使用 `Flow` 命名。
|
||||
|
||||
奖励选择约束:
|
||||
- 满血奖励选择结果只写入结算上下文。
|
||||
- 不直接写入局内资源管理器。
|
||||
- 最终由结束状态链统一合并到玩家背包。
|
||||
|
||||
---
|
||||
|
||||
## 8. 核心不变量(必须保持)
|
||||
|
||||
1. `CombatScheduler` 只做状态机管理与共享运行时收口,不继续吸收具体业务细节。
|
||||
2. `CombatNodeComponent` 不再持有战斗内资源真值。
|
||||
3. 局内 `Coin / Gold / BaseHp / Loot Backpack / BuildTowerSnapshots` 以 `CombatRunResourceStore` 为唯一真值来源。
|
||||
4. 组件产出规则以 `InventoryGenerationComponent` 为统一运行时入口;战斗掉落与奖励候选都通过它生成。
|
||||
5. 存活敌人数与 `HasAliveBoss` 以 `EnemyLifecycleTracker` 为唯一真值来源。
|
||||
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 新增敌人掉落规则
|
||||
|
||||
优先改 `InventoryGenerationComponent` 及其下层规则模块,不要在 `EnemyManager`、`CombatScheduler` 或状态类里直接计算掉落。
|
||||
|
||||
### 10.3.x 新增奖励候选规则
|
||||
|
||||
优先改 `InventoryGenerationComponent`、`RewardCandidateBuilder` 或 `DropPoolRoller`,不要在结算状态链里复制一套候选生成规则。
|
||||
|
||||
### 10.4 新增战斗内资源或建塔快照规则
|
||||
|
||||
优先改 `CombatRunResourceStore`,不要回流到 `CombatNodeComponent`。
|
||||
|
||||
### 10.5 新增地图/战斗基础 UI 加载规则
|
||||
|
||||
优先改 `CombatLoadSession` 或 `CombatLoadingState`,不要把加载细节塞回 `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 / 运行时数据”分工执行?
|
||||
|
||||
---
|
||||
|
||||
## 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` 不变 |
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,63 @@
|
||||
# 《几何塔防》
|
||||
|
||||
## 游戏定位
|
||||
塔防肉鸽
|
||||
|
||||
## 游戏主循环
|
||||
1. 进入游戏,使用当前样例库存中的组件组装初始防御塔并开始游戏
|
||||
2. 在关卡中玩家选择不同的节点推进关卡:
|
||||
- 战斗节点:布置防御塔抵御敌人进攻并收集防御塔组件
|
||||
- 事件节点:随机事件(不含战斗)
|
||||
- 商店节点:购买防御塔组件
|
||||
3. 节点后调整:玩家可使用三组件自由组装防御塔以抵御更强的敌人进攻
|
||||
4. 开始新一轮关卡
|
||||
|
||||
## 具体说明
|
||||
### 一、战前准备:
|
||||
1. 当前 M1 以样例库存和仓库内三组件组装链为准,不再要求独立的“开局二选三组件并组出两座塔”前置流程
|
||||
|
||||
### 二、节点:
|
||||
1. 当前 M1 只实现单一固定 Run:每个大关固定 10 个节点,最后一个节点固定为 Boss 战斗节点;多主题地图与大关间选择保留到后续阶段
|
||||
2. 主题地图示例(后续阶段):
|
||||
- 火山:高温(战斗节点中会随机触发火山喷发在地图上生成岩浆格)
|
||||
- 对于防御塔:部分组件在该高温下能发挥更强/更弱性能,若岩浆生成在防御塔上将会进一步强化高温对组件性能的影响
|
||||
- 对于敌人:敌人多具有火焰抗性,部分敌人能在岩浆格上更快的行走
|
||||
- 山地:地势起伏(地图格子有额外的高度条件,悬崖格子)
|
||||
- 对于防御塔:不同高度的攻击会有攻击范围变化,高打低范围加强,低打高范围缩小
|
||||
- 对于敌人:不同高度会有移动速度的差异,高往低走移速加快,低往高走移速降低,陆地敌人被击退到悬崖格子立即死亡
|
||||
3. 当前每个大关有 10 个固定节点,完成 Boss 节点后进入正式结束态并返回主菜单,不在 M1 内继续展开下一大关选择
|
||||
|
||||
#### 1. 战斗节点
|
||||
1. 玩家携带一定数量的防御塔进入关卡,在关卡内规定的位置布置防御塔,具体的游戏逻辑与一般的塔防游戏类似:
|
||||
- 关卡开始有一些资源用于布置防御塔,击杀敌人获取资源来布置或升级防御塔。
|
||||
- 敌人会选择最短路径由出怪口向玩家基地前进;道路阻挡与更复杂的路径改写机制保留到后续阶段
|
||||
2. 击杀敌人除了获取关卡内使用的资源外,还有概率掉落防御塔组件;每个小关卡结束后也会奖励组件与金币用于后续节点
|
||||
3. 关卡内设定一个胜利波次,当玩家存活的波次达到后会根据基地生命产生不同的结算:
|
||||
- = 100% :获得额外 30% 的金币,以及额外 1 次组件 3 选 1
|
||||
- >= 80% :获得额外 10% 的金币
|
||||
- >= 50% :无加成
|
||||
- < 50%:当前 M1 不再追加额外耐久惩罚;耐久已按“每场战斗结算后对本场参战塔固定扣 1”收口
|
||||
4. “胜利后继续挑战”保留到后续阶段,当前 M1 以正常结算回流节点地图为准
|
||||
|
||||
#### 2. 事件节点
|
||||
玩家经历一些有选项的随机事件,获取额外的奖励/惩罚。
|
||||
|
||||
示例:
|
||||
1. 玩家花费 100 金币赌马,有两个选择:(1) 30% 赢,赢了获得 250 金币。(2) 70% 赢,赢了获得 150 金币
|
||||
2. 玩家提供 2 个防御塔组件,获得 1 个不低于原来品质的防御塔组件
|
||||
3. 耐久换金币事件保留到后续阶段;当前 M1 只保留最小耐久闭环
|
||||
|
||||
#### 3. 商店节点
|
||||
1. 当前 M1 只实现组件商店的基础购买;商店内出售、刷新、复杂定价、卖塔加成与耐久折价保留到后续阶段
|
||||
2. 道具系统保留到后续阶段
|
||||
|
||||
### 三、节点后的调整
|
||||
1. 组装防御塔:每个防御塔都必须有枪口(攻击组件)、轴承(旋转组件)、底座(功能组件)三个组件,防御塔的品质由组件决定。当前 M1 已实现三组件完整合法参战、品质统一计算、组件实例 Tag 生成、塔级 Tag 汇总,以及首发 7 个 Tag 的战斗效果
|
||||
- 组件功能(某些组件还有全局性的属性倍率,比如高伤害穿透攻击的枪口会绑一个 0.5x攻击速度 的属性倍率来约束防御塔性能):
|
||||
- 枪口(攻击组件):决定攻击伤害,攻击方式(普通子弹、范围伤害、穿透激光……)
|
||||
- 轴承(旋转组件):决定枪口转速(某些攻击方式只有对准敌人后才能进行攻击),攻击范围
|
||||
- 底座(功能组件):决定攻击频率,攻击属性(火焰、毒素、冰……)
|
||||
- 品质计算:每个组件提供一定的品质权重(白:1,绿:2,蓝:3,紫:4,红:5),比如三个组件是 2 绿 1 白,那么防御塔的品质是 (2+2+1)/3=1.67,四舍五入后为 2 也就是绿色品质。
|
||||
- 各品质的配件槽与更深的配件系统保留到后续阶段
|
||||
- 组件 Tag 当前正式采用 `Tag.txt + RarityTagBudget.txt + TagConfig.txt` 三表方案:`Tag.txt` 负责基础字典、生成门槛、权重与启用态,`RarityTagBudget.txt` 负责按品质的 Tag 数量预算,`TagConfig.txt` 负责触发阶段、描述与效果参数
|
||||
2. 拆解与耐久:当前 M1 只保留最小耐久闭环,即每场战斗结算后按本场参战塔真实扣减 `1` 点耐久、`0` 耐久失效并拦截参战 / 战斗入口;连续属性衰减、自动销毁与维修系统保留到后续阶段
|
||||
@@ -0,0 +1,667 @@
|
||||
# 程序集三层拆分方案
|
||||
|
||||
最后更新:2026-04-30
|
||||
|
||||
## 1. 设计目标
|
||||
|
||||
将项目拆分为三层,逐步解耦 Unity 依赖,实现核心业务逻辑的可测试性和可移植性:
|
||||
|
||||
- **L0(Domain)**:纯 C# 业务层,引用 GameFramework.dll 作为基础设施,可在独立解决方案中构建
|
||||
- **L1(Infrastructure)**:胶水层,连接 L0 与 Unity Runtime 类型
|
||||
- **L2(Presentation)**:表现层,Unity MonoBehaviour、UGuiForm、Entity 实现
|
||||
|
||||
---
|
||||
|
||||
## 2. GameFramework.dll 复用
|
||||
|
||||
项目自带的 `Assets/GameFramework/Libraries/GameFramework.dll` 是 **纯 C# 实现**的 GameFramework 核心库,包含 19 个模块。L0 直接引用此 DLL,无需重新实现。
|
||||
|
||||
### 2.1 可直接使用的模块
|
||||
|
||||
| 模块 | 提供内容 | L0 使用方式 |
|
||||
|------|---------|-----------|
|
||||
| **Event** | `EventManager`, `GameEventArgs` | `GameEntry.Event` 替换为 `EventManager` |
|
||||
| **ObjectPool** | `ObjectPoolManager`, `ObjectBase` | 继承 `ObjectBase`,无需自己实现池 |
|
||||
| **Fsm** | `FsmManager`, `FsmState`, `FsmState<T>` | 继承 `FsmState<T>` 构建状态机 |
|
||||
| **ReferencePool** | `ReferencePool` | `ReferencePool.Acquire<T>()` / `Release()` |
|
||||
| **DataNode** | 树状数据结构 | 直接使用 |
|
||||
| **Utility** | 通用工具类 | 直接使用 |
|
||||
| **Config** | 配置管理 | 直接使用 |
|
||||
| **DataTable** | 表格加载解析 | 数据行类依赖 GameFramework |
|
||||
|
||||
### 2.2 需要 Unity 适配的模块
|
||||
|
||||
以下模块需要 L1 提供 Unity 特定实现:
|
||||
|
||||
| 模块 | 原因 | L1 适配职责 |
|
||||
|------|------|------------|
|
||||
| **Resource** | 依赖 Unity Resources/AssetDatabase | 实现 `IResourceManager` |
|
||||
| **Scene** | 依赖 Unity SceneManager | 实现 `ISceneManager` |
|
||||
| **Entity** | 依赖 Unity GameObject | 实现 `IEntityManager` |
|
||||
| **UI** | 依赖 Unity UGUI | 实现 `IUIFormManager` |
|
||||
| **Sound** | 依赖 Unity Audio | 实现 `ISoundManager` |
|
||||
|
||||
### 2.3 复用带来的简化
|
||||
|
||||
```
|
||||
传统方案(自研基础设施)
|
||||
├── 需要自己实现事件系统
|
||||
├── 需要自己实现对象池基类
|
||||
├── 需要自己实现状态机框架
|
||||
└── 大量基础设施代码
|
||||
|
||||
GameFramework.dll 方案
|
||||
├── 事件 → GameFramework.Event.EventManager
|
||||
├── 对象池 → GameFramework.ObjectPool
|
||||
├── 状态机 → GameFramework.Fsm
|
||||
└── 专注业务逻辑实现
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 三层职责定义
|
||||
|
||||
### L0 - Domain(纯 C# 业务层)
|
||||
|
||||
- 引用 `GameFramework.dll`,使用其提供的 Event/ObjectPool/Fsm 等基础设施
|
||||
- 包含所有业务规则、状态机、领域逻辑
|
||||
- 无 `using UnityEngine`、`using UnityGameFramework.Runtime`
|
||||
- 通过接口与 L1 通信
|
||||
- 在独立 .sln 中构建,输出 DLL 导入 Unity
|
||||
|
||||
### L1 - Infrastructure(胶水层)
|
||||
|
||||
- 实现 GameFramework 的 Unity 特定接口(Resource/Scene/Entity/UI/Sound)
|
||||
- 实现 L0 定义的扩展接口(如 `ICombatEventHandler`)
|
||||
- 持有 L0 服务实例,管理 Unity 生命周期
|
||||
- 直接依赖 UnityEngine 和 GameFramework.Runtime
|
||||
|
||||
### L2 - Presentation(表现层)
|
||||
|
||||
- 所有 `MonoBehaviour` 类
|
||||
- View 层(UGuiForm 具体实现)
|
||||
- Entity Logic(Player、Enemy、Tower 具体实体)
|
||||
- ECS 组件(MovementComponent、ShooterBullet 等)
|
||||
|
||||
---
|
||||
|
||||
## 4. 程序集映射
|
||||
|
||||
### 4.1 L0 程序集
|
||||
|
||||
```
|
||||
GeometryTD.Domain/ ← 引用 GameFramework.dll
|
||||
├── Definition/
|
||||
│ ├── Enum/ # 所有枚举类型
|
||||
│ ├── Constant/ # 常量定义
|
||||
│ ├── DataStruct/ # 纯数据结构(AttackPayload, TowerStatsData 等)
|
||||
│ └── Tag/
|
||||
│ ├── Aggregation/ # Tag 汇总服务
|
||||
│ ├── Generation/ # Tag 生成规则
|
||||
│ ├── Metadata/ # Tag 定义元数据
|
||||
│ └── Combat/ # Tag 效果解析
|
||||
│
|
||||
├── GameFramework/ # GameFramework.dll 直接使用
|
||||
│ └── Event/ # 自定义事件 args,继承 GameEventArgs
|
||||
│
|
||||
├── CustomComponent/
|
||||
│ ├── CombatNode/ # 战斗域
|
||||
│ │ ├── CombatScheduler # 基于 GameFramework.Fsm
|
||||
│ │ ├── EnemyManager # 敌人生成、追踪
|
||||
│ │ ├── CombatRunResourceStore # 战斗资源存储
|
||||
│ │ └── CombatSettlementCalculator
|
||||
│ ├── PlayerInventory/ # 背包、交易、组装服务
|
||||
│ └── InventoryGeneration/ # 掉落、商店、奖励生成
|
||||
│
|
||||
├── UI/
|
||||
│ ├── Base/
|
||||
│ │ ├── IUIUseCase.cs
|
||||
│ │ └── UIContext.cs
|
||||
│ ├── Combat/
|
||||
│ │ ├── UseCase/ # CombatSelectFormUseCase, CombatInfoFormUseCase
|
||||
│ │ ├── RawData/
|
||||
│ │ └── Context/
|
||||
│ ├── Game/
|
||||
│ │ ├── UseCase/ # EventFormUseCase, NodeMapFormUseCase, RepoFormUseCase
|
||||
│ │ ├── RawData/
|
||||
│ │ └── Context/
|
||||
│ └── General/
|
||||
│ ├── UseCase/
|
||||
│ ├── RawData/
|
||||
│ └── Context/
|
||||
│
|
||||
└── Utility/
|
||||
├── InventoryCloneUtility.cs
|
||||
├── EnumUtility.cs
|
||||
└── InventoryRarityRuleService.cs
|
||||
```
|
||||
|
||||
### 4.2 L1 程序集
|
||||
|
||||
```
|
||||
GeometryTD.Infrastructure/
|
||||
├── GameFramework/ # GameFramework Unity 适配
|
||||
│ ├── Resource/ # 实现 IResourceManager
|
||||
│ ├── Scene/ # 实现 ISceneManager
|
||||
│ ├── Entity/ # 实现 IEntityManager
|
||||
│ ├── UI/ # 实现 IUIFormManager
|
||||
│ └── Sound/ # 实现 ISoundManager
|
||||
│
|
||||
├── CustomComponent/
|
||||
│ ├── CombatNode/
|
||||
│ │ └── CombatNodeComponent.cs # Unity Component
|
||||
│ ├── PlayerInventory/
|
||||
│ │ └── PlayerInventoryComponent.cs
|
||||
│ ├── InventoryGeneration/
|
||||
│ │ └── InventoryGenerationComponent.cs
|
||||
│ ├── EventNodeComponent.cs
|
||||
│ ├── ShopNodeComponent.cs
|
||||
│ ├── TagRegistry/
|
||||
│ │ └── TagRegistryComponent.cs
|
||||
│ └── BuiltinDataComponent.cs
|
||||
│
|
||||
├── Scene/
|
||||
│ └── Map/
|
||||
│ ├── MapTopologyService.cs # Tilemap 扫描
|
||||
│ ├── TowerPlacementService.cs # 依赖 GameEntry.Entity
|
||||
│ ├── TowerSelectionPresenter.cs
|
||||
│ └── MapCombatRuntimeBridge.cs
|
||||
│
|
||||
├── Entity/
|
||||
│ ├── EntityLogic/
|
||||
│ │ ├── EntityBase.cs
|
||||
│ │ ├── CombatSelectInputService.cs
|
||||
│ │ ├── CombatSelectUseCaseConfigurator.cs
|
||||
│ │ └── MapEntity.cs
|
||||
│ ├── EntityData/ # Unity 可序列化
|
||||
│ │ ├── MapData.cs
|
||||
│ │ ├── TowerData.cs
|
||||
│ │ ├── EnemyData.cs
|
||||
│ │ └── BulletData.cs
|
||||
│ └── EntityExtension.cs
|
||||
│
|
||||
├── UI/
|
||||
│ ├── Base/ # Unity 相关基类
|
||||
│ │ ├── UGuiForm.cs
|
||||
│ │ ├── UGuiGroupHelper.cs
|
||||
│ │ ├── UIFormControllerCommonBase.cs
|
||||
│ │ ├── UIExtension.cs
|
||||
│ │ └── UIFormControllerBase.cs
|
||||
│ └── Combat/
|
||||
│ └── Controller/
|
||||
│
|
||||
├── DataTable/ # GameFramework.DataTable 依赖
|
||||
│ └── DR*.cs
|
||||
│
|
||||
└── Procedure/ # GameFramework.Procedure
|
||||
└── ProcedureMain/
|
||||
```
|
||||
|
||||
### 4.3 L2 程序集
|
||||
|
||||
```
|
||||
GeometryTD.Presentation/
|
||||
├── UI/
|
||||
│ ├── Combat/
|
||||
│ │ └── View/
|
||||
│ ├── Game/
|
||||
│ │ └── View/
|
||||
│ ├── General/
|
||||
│ │ └── View/
|
||||
│ ├── Templates/
|
||||
│ └── Common/
|
||||
│
|
||||
├── Entity/
|
||||
│ └── EntityLogic/
|
||||
│ ├── Player.cs
|
||||
│ ├── Enemy.cs
|
||||
│ ├── TowerEntity.cs
|
||||
│ ├── BulletEntity.cs
|
||||
│ └── EnemyTagStatusRuntime.cs
|
||||
│
|
||||
└── Components/
|
||||
├── MovementComponent.cs
|
||||
├── ShooterBullet.cs
|
||||
├── ShooterMuzzleComp.cs
|
||||
├── TowerController.cs
|
||||
├── InputComponent.cs
|
||||
├── BasicBaseComp.cs
|
||||
└── BasicBearingComp.cs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. GameFramework 集成方式
|
||||
|
||||
### 5.1 事件系统
|
||||
|
||||
L0 使用 GameFramework 内置的 `EventManager`,无需自己实现事件系统:
|
||||
|
||||
```csharp
|
||||
// L0: 定义游戏事件,继承 GameFramework.Event.GameEventArgs
|
||||
public class CombatCoinChangedEventArgs : GameEventArgs
|
||||
{
|
||||
public const int EventId = typeof(CombatCoinChangedEventArgs).GetHashCode();
|
||||
|
||||
public int CurrentCoin { get; private set; }
|
||||
public int Delta { get; private set; }
|
||||
|
||||
public CombatCoinChangedEventArgs() { }
|
||||
|
||||
public CombatCoinChangedEventArgs(int currentCoin, int delta)
|
||||
{
|
||||
CurrentCoin = currentCoin;
|
||||
Delta = delta;
|
||||
}
|
||||
}
|
||||
|
||||
// L0: 服务中使用
|
||||
public class CombatRunResourceStore
|
||||
{
|
||||
private IEventManager _event;
|
||||
|
||||
public CombatRunResourceStore(IEventManager eventManager)
|
||||
{
|
||||
_event = eventManager;
|
||||
}
|
||||
|
||||
public void AddCoin(int amount)
|
||||
{
|
||||
CurrentCoin += amount;
|
||||
_event.Fire(this, CombatCoinChangedEventArgs.Create(CurrentCoin, amount));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 状态机
|
||||
|
||||
L0 使用 GameFramework 的 Fsm 模块:
|
||||
|
||||
```csharp
|
||||
// L0: 战斗状态机基于 GameFramework.Fsm
|
||||
public interface ICombatFsm { } // 空接口,用于泛型约束
|
||||
|
||||
public class CombatScheduler
|
||||
{
|
||||
private IFsmManager _fsmManager;
|
||||
private CombatSchedulerRuntime _runtime;
|
||||
|
||||
public CombatScheduler(IFsmManager fsmManager)
|
||||
{
|
||||
_fsmManager = fsmManager;
|
||||
_runtime = new CombatSchedulerRuntime();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_fsmManager.CreateFsm<ICombatFsm>(this,
|
||||
new CombatLoadingState(),
|
||||
new CombatRunningPhaseState(),
|
||||
new CombatWaitingForPhaseEndState(),
|
||||
new CombatSettlementState());
|
||||
}
|
||||
}
|
||||
|
||||
// L0: 具体状态继承 FsmState
|
||||
public class CombatRunningPhaseState : FsmState<ICombatFsm>
|
||||
{
|
||||
protected internal override void OnEnter(ICombatFsm fsmOwner)
|
||||
{
|
||||
// 初始化
|
||||
}
|
||||
|
||||
protected internal override void OnUpdate(ICombatFsm fsmOwner, float elapseSeconds)
|
||||
{
|
||||
// 每帧更新
|
||||
}
|
||||
|
||||
protected internal override void OnLeave(ICombatFsm fsmOwner, bool isShutdown)
|
||||
{
|
||||
// 清理
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 对象池
|
||||
|
||||
L0 使用 GameFramework 的 ObjectPool:
|
||||
|
||||
```csharp
|
||||
// L0: 敌人继承 ObjectBase
|
||||
public class EnemyObject : ObjectBase
|
||||
{
|
||||
public int EnemyId { get; private set; }
|
||||
public int Health { get; private set; }
|
||||
|
||||
protected internal override void OnSpawn(bool isRecycle)
|
||||
{
|
||||
// 激活时调用
|
||||
}
|
||||
|
||||
protected internal override void OnDespawn(bool isRecycle)
|
||||
{
|
||||
// 回收时调用
|
||||
}
|
||||
|
||||
public void Initialize(int enemyId, int health)
|
||||
{
|
||||
EnemyId = enemyId;
|
||||
Health = health;
|
||||
}
|
||||
}
|
||||
|
||||
// L0: 使用对象池
|
||||
public class EnemyManager
|
||||
{
|
||||
private IObjectPoolManager _poolManager;
|
||||
|
||||
public EnemyManager(IObjectPoolManager poolManager)
|
||||
{
|
||||
_poolManager = poolManager;
|
||||
}
|
||||
|
||||
public void SpawnEnemy(int enemyId, int health)
|
||||
{
|
||||
var pool = _poolManager.GetOrCreateObjectPool<EnemyObject>("EnemyPool");
|
||||
var enemy = EnemyObject.Create(enemyId, health);
|
||||
pool.Register(enemy, true);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. L1 桥接设计
|
||||
|
||||
### 6.1 GameFramework Unity 适配接口
|
||||
|
||||
GameFramework.dll 定义了以下接口,L1 需要提供 Unity 实现:
|
||||
|
||||
```csharp
|
||||
// GameFramework 定义的接口(L0 引用)
|
||||
namespace GameFramework.Resource
|
||||
{
|
||||
public interface IResourceManager
|
||||
{
|
||||
void LoadAsset(string assetName, LoadAssetCallbacks callbacks, object userData);
|
||||
void UnloadAsset(string assetName);
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// L1: Unity 实现
|
||||
public class UnityResourceManager : IResourceManager
|
||||
{
|
||||
public void LoadAsset(string assetName, LoadAssetCallbacks callbacks, object userData)
|
||||
{
|
||||
// 使用 Unity Resources.Load 或 Addressables
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 L0 服务生命周期管理
|
||||
|
||||
```csharp
|
||||
// L1: Unity Component 持有 L0 服务实例
|
||||
public class CombatNodeComponent : GameFrameworkComponent
|
||||
{
|
||||
private IEventManager _eventManager;
|
||||
private IObjectPoolManager _poolManager;
|
||||
private IFsmManager _fsmManager;
|
||||
|
||||
// L0 服务
|
||||
private CombatScheduler _scheduler;
|
||||
private EnemyManager _enemyManager;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// 初始化 GameFramework Unity 适配器
|
||||
_eventManager = GameEntry.GetComponent<EventComponent>();
|
||||
_poolManager = GameEntry.GetComponent<ObjectPoolComponent>();
|
||||
_fsmManager = GameEntry.GetComponent<FsmComponent>();
|
||||
|
||||
// 初始化 L0 服务(注入依赖)
|
||||
_enemyManager = new EnemyManager(_poolManager);
|
||||
_scheduler = new CombatScheduler(_fsmManager, _enemyManager);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Unity 类型处理策略
|
||||
|
||||
### 7.1 Vector3 / Quaternion / Color
|
||||
|
||||
| 类型 | 方案 |
|
||||
|------|------|
|
||||
| `Vector3` | 使用 `System.Numerics.Vector3`,GameFramework 内部已使用 |
|
||||
| `Quaternion` | 使用 `System.Numerics.Quaternion` |
|
||||
| `Color` | 定义纯 C# Color 结构 `{ float r, g, b, a; }` |
|
||||
|
||||
### 7.2 [Serializable]
|
||||
|
||||
```csharp
|
||||
// L0: POCO 数据结构
|
||||
public class TowerStatsData
|
||||
{
|
||||
public int[] AttackDamage { get; set; }
|
||||
public float[] AttackSpeed { get; set; }
|
||||
}
|
||||
|
||||
// L1: Unity 可序列化 DTO
|
||||
[Serializable]
|
||||
public class TowerStatsDataDto
|
||||
{
|
||||
[SerializeField] private int[] _attackDamage;
|
||||
[SerializeField] private float[] _attackSpeed;
|
||||
|
||||
public TowerStatsData ToDomain() => new()
|
||||
{
|
||||
AttackDamage = _attackDamage,
|
||||
AttackSpeed = _attackSpeed
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 Sprite 引用
|
||||
|
||||
```csharp
|
||||
// L0: 使用资源路径而非 Sprite 引用
|
||||
public class TowerSelectItemRawData
|
||||
{
|
||||
public string IconPath { get; set; } // "UI/Icons/TowerIcon"
|
||||
}
|
||||
|
||||
// L1: Controller 负责路径到 Sprite 的解析
|
||||
public class CombatSelectFormController
|
||||
{
|
||||
private SpriteCacheComponent _spriteCache;
|
||||
|
||||
private TowerSelectItemContext BuildContext(TowerSelectItemRawData raw)
|
||||
{
|
||||
return new TowerSelectItemContext
|
||||
{
|
||||
Icon = _spriteCache.GetSprite(raw.IconPath)
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 迁移顺序
|
||||
|
||||
### Phase 1: 基础设施搭建
|
||||
|
||||
| 任务 | 说明 |
|
||||
|------|------|
|
||||
| 创建 L0 项目,引用 GameFramework.dll | 验证基础依赖 |
|
||||
| 验证 GameFramework Event/Fsm/ObjectPool 可用 | 核心模块连通性测试 |
|
||||
| 创建 L1 基础结构 | Unity Component 基类、GameFramework 适配器 |
|
||||
|
||||
### Phase 2: 核心业务迁移(低风险优先)
|
||||
|
||||
| 迁移项 | 说明 | 依赖 |
|
||||
|--------|------|------|
|
||||
| `Definition/Enum/*` | 枚举类型 | 无 |
|
||||
| `Definition/Constant/*` | 常量定义 | 无 |
|
||||
| `UI/*/RawData/*` | 原始数据 | 无 |
|
||||
| `UI/*/Context/*` | 上下文 | 无 |
|
||||
| `Utility/*` | 工具类 | 无 |
|
||||
|
||||
### Phase 3: 业务域迁移
|
||||
|
||||
| 迁移项 | 说明 | 依赖 |
|
||||
|--------|------|------|
|
||||
| `InventoryGeneration/*` | 掉落、商店、奖励 | Phase 1-2 |
|
||||
| `PlayerInventory/*` | 背包、交易、组装 | Phase 1-2 |
|
||||
| `UI/*/UseCase/*` | 用例 | Phase 2 + Sprite 路径化 |
|
||||
| `Definition/Tag/*` | Tag 系统 | Phase 1-2 |
|
||||
|
||||
### Phase 4: 战斗域(核心难点)
|
||||
|
||||
| 迁移项 | 说明 | 依赖 |
|
||||
|--------|------|------|
|
||||
| `CombatNode/CombatScheduler` | 状态机 | GameFramework.Fsm |
|
||||
| `CombatNode/EnemyManager/*` | 敌人域 | GameFramework.ObjectPool |
|
||||
| `CombatNode/CombatRunResourceStore` | 资源存储 | GameFramework.Event |
|
||||
| `CombatNode/CombatSettlementCalculator` | 结算 | Phase 3 |
|
||||
|
||||
### Phase 5: 胶水和表现层迁移
|
||||
|
||||
| 迁移项 | 说明 |
|
||||
|--------|------|
|
||||
| `CustomComponent/*Component` | Unity Component |
|
||||
| `UI/Base/*` | Controller 基类 |
|
||||
| `UI/*/Controller/*` | Controller 实现 |
|
||||
| `UI/*/View/*` | View 实现 |
|
||||
| `Entity/EntityLogic/*` | Entity 实现 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 项目文件组织
|
||||
|
||||
### 9.1 L0 项目文件
|
||||
|
||||
```xml
|
||||
<!-- GeometryTD.Domain.csproj -->
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>GeometryTD.Domain</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="GameFramework">
|
||||
<HintPath>..\..\Assets\GameFramework\Libraries\GameFramework.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
```
|
||||
|
||||
### 9.2 L1 项目文件
|
||||
|
||||
```xml
|
||||
<!-- GeometryTD.Infrastructure.csproj -->
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GeometryTD.Domain\GeometryTD.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>Unity\Editor\Data\Managed\UnityEngine\UnityEngine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityGameFramework.Runtime">
|
||||
<!-- Unity GameFramework Runtime 引用 -->
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
```
|
||||
|
||||
### 9.3 Unity 资产结构
|
||||
|
||||
```
|
||||
Assets/
|
||||
├── GameFramework/
|
||||
│ └── Libraries/
|
||||
│ ├── GameFramework.dll ← L0 直接引用
|
||||
│ └── GameFramework.xml ← 文档
|
||||
│
|
||||
├── GameMain/
|
||||
│ ├── L0/ # L0 DLL 输出
|
||||
│ ├── L1/ # L1 源码或 DLL
|
||||
│ └── Scripts/
|
||||
│ └── L2/ # L2 表现层
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 验收标准
|
||||
|
||||
1. **L0 可独立编译**:不包含 UnityEngine.dll、UnityGameFramework.Runtime 引用
|
||||
2. **GameFramework.dll 正确引用**:L0 可使用 Event/ObjectPool/Fsm/ReferencePool
|
||||
3. **无循环依赖**:L2 → L1 → L0,单向依赖
|
||||
4. **接口隔离**:L0 与 Unity 的交互通过 L1 适配器
|
||||
5. **游戏流程完整**:拆分后战斗、商店、组装流程正常运行
|
||||
|
||||
---
|
||||
|
||||
## 11. 附录:GameFramework.dll 模块清单
|
||||
|
||||
```
|
||||
GameFramework.dll 包含以下 19 个模块(纯 C# 实现):
|
||||
|
||||
配置与数据
|
||||
├── Config - 全局配置管理
|
||||
├── DataNode - 树状数据结点
|
||||
├── DataTable - 表格数据管理
|
||||
└── Setting - 键值对存储
|
||||
|
||||
核心设施
|
||||
├── Event - 事件管理(EventPool)
|
||||
├── ObjectPool - 对象池(ObjectPoolManager)
|
||||
├── ReferencePool - 引用计数池
|
||||
├── Fsm - 有限状态机
|
||||
└── Procedure - 流程(ProcedureBase)
|
||||
|
||||
资源管理
|
||||
├── Resource - 资源加载(需要 Unity 适配器)
|
||||
├── Scene - 场景管理(需要 Unity 适配器)
|
||||
├── Entity - 实体管理(需要 Unity 适配器)
|
||||
├── UI - 界面管理(需要 Unity 适配器)
|
||||
└── Sound - 声音管理(需要 Unity 适配器)
|
||||
|
||||
网络与下载
|
||||
├── Network - Socket 长连接
|
||||
├── WebRequest - HTTP 短连接
|
||||
└── Download - 文件下载
|
||||
|
||||
辅助模块
|
||||
├── Localization - 多语言(需要资源适配器)
|
||||
├── FileSystem - 虚拟文件系统
|
||||
├── Debugger - 调试窗口
|
||||
└── Utility - 通用工具类
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 附录:当前 Unity 依赖渗透点
|
||||
|
||||
以下文件包含 `using UnityEngine` 或 `using UnityGameFramework.Runtime`,需要迁移:
|
||||
|
||||
| 文件 | Unity 依赖 | 目标层 |
|
||||
|------|-----------|-------|
|
||||
| `TowerPlacementService.cs` | `GameEntry.Entity` | L1 |
|
||||
| `MapTopologyService.cs` | `Tilemap`, `Vector3Int` | L1 |
|
||||
| `CombatSelectFormUseCase.cs` | `UnityEngine.Sprite` | L0 → 路径化 |
|
||||
| `TowerStatsData.cs` | `[Serializable]`, `Color` | L0 → POCO + DTO |
|
||||
| `AttackPayload.cs` | `Vector3` | L0 → System.Numerics |
|
||||
| `MapEntity.cs` | `MonoBehaviour` | L1 |
|
||||
| `EnemyEntity.cs` | `Transform` | L2 |
|
||||
| `GameEntry.Builtin.cs` | `GameFrameworkComponent` | L1 |
|
||||
@@ -0,0 +1,199 @@
|
||||
# 《几何塔防》MVP 范围说明(流程验证版)
|
||||
|
||||
---
|
||||
|
||||
## 一、MVP目标
|
||||
|
||||
本阶段目标:
|
||||
|
||||
> 验证游戏完整流程是否可运行,包括
|
||||
> 战斗节点 → 事件节点 → 商店节点 → 节点后组装 → 下一节点
|
||||
> 直至完成一大关。
|
||||
|
||||
本阶段不关注:
|
||||
|
||||
* 数值平衡
|
||||
* 构筑深度
|
||||
* 美术质量
|
||||
* 商业化系统
|
||||
* 长期留存
|
||||
|
||||
---
|
||||
|
||||
## 二、本阶段包含内容
|
||||
|
||||
---
|
||||
|
||||
### 1️⃣ 基础游戏结构
|
||||
|
||||
* 单一主题地图(无环境机制)
|
||||
* 1个大关(固定10节点)
|
||||
* 最后节点为Boss战
|
||||
* 固定节点顺序(例如:战斗 → 事件 → 战斗 → 商店 → 战斗 → Boss)
|
||||
|
||||
不做节点地图选择 UI。
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ 战斗节点(核心可运行)
|
||||
|
||||
包含:
|
||||
|
||||
* 基地生命系统
|
||||
* 固定路径(单路径)
|
||||
* 敌人按最短路径移动
|
||||
* 5~8波敌人
|
||||
* 1种普通敌人 + 1种精英敌人 + 1种Boss
|
||||
* 胜利条件:达到波次
|
||||
* 失败条件:基地血量为0
|
||||
|
||||
战斗奖励:
|
||||
|
||||
* 敌人可概率掉落组件与金币
|
||||
* 战斗结算提供金币奖励
|
||||
* 基地满血通关时额外提供 1 次组件 3选1 奖励
|
||||
|
||||
不做:
|
||||
|
||||
* 多路径
|
||||
* 地图机制
|
||||
* 精细敌人AI
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ 事件节点(流程占位)
|
||||
|
||||
实现:
|
||||
|
||||
* 3个固定事件模板
|
||||
* 简单二选一结构
|
||||
* 直接修改金币或组件数量
|
||||
|
||||
例如:
|
||||
|
||||
* 获得100金币
|
||||
* 损失1个随机组件换取高品质组件
|
||||
|
||||
不做:
|
||||
|
||||
* 复杂概率算法
|
||||
* 连锁事件
|
||||
* 条件触发事件
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ 商店节点
|
||||
|
||||
实现:
|
||||
|
||||
* 显示4个随机组件
|
||||
* 可购买组件
|
||||
|
||||
不做:
|
||||
|
||||
* 商店内出售组件
|
||||
* 商店刷新
|
||||
* 动态定价
|
||||
* 经济平衡
|
||||
* 道具系统
|
||||
* 广告
|
||||
* 内购
|
||||
|
||||
---
|
||||
|
||||
### 5️⃣ 节点后组装系统
|
||||
|
||||
实现:
|
||||
|
||||
* 组件栏
|
||||
* 塔槽位
|
||||
* 拖拽组装
|
||||
* 组件替换
|
||||
* 基础属性与 Tag 展示
|
||||
|
||||
组件结构(精简):
|
||||
|
||||
* 枪口
|
||||
* 轴承
|
||||
* 底座
|
||||
* 基础 Tag 系统(首发 7 个:`Fire`、`Ice`、`Crit`、`Execution`、`Shatter`、`Inferno`、`AbsoluteZero`)
|
||||
|
||||
不做:
|
||||
|
||||
* 完整维修 / 折价 / 自动销毁系统
|
||||
* 高级 Tag 联动
|
||||
* 复杂触发矩阵
|
||||
|
||||
---
|
||||
|
||||
## 三、明确本阶段不做内容
|
||||
|
||||
以下内容全部排除在本阶段之外:
|
||||
|
||||
* ❌ 多主题地图
|
||||
* ❌ 地图机制(火山/山地)
|
||||
* ❌ 局外成长系统
|
||||
* ❌ 广告系统
|
||||
* ❌ 内购系统
|
||||
* ❌ 成就系统
|
||||
* ❌ 排行榜
|
||||
* ❌ 多流派深度平衡
|
||||
* ❌ 大规模敌人种类
|
||||
* ❌ 复杂Boss阶段机制
|
||||
* ❌ 数值精细调优
|
||||
* ❌ 高级特效优化
|
||||
|
||||
---
|
||||
|
||||
## 四、组件规模限制
|
||||
|
||||
为避免膨胀,本阶段限制:
|
||||
|
||||
* 总组件数量 ≤ 20
|
||||
* Tag数量 ≤ 8
|
||||
* 品质等级:白 / 绿 / 蓝 / 紫 / 红
|
||||
* 仅要求三组件主结构,不扩展更深的配件槽系统
|
||||
|
||||
---
|
||||
|
||||
## 五、UI范围
|
||||
|
||||
包含:
|
||||
|
||||
* 主界面(开始游戏)
|
||||
* 节点流程界面
|
||||
* 战斗界面
|
||||
* 商店界面
|
||||
* 组装界面
|
||||
* 结算界面
|
||||
|
||||
允许:
|
||||
|
||||
* 使用临时UI
|
||||
* 使用占位图
|
||||
* 不做动画优化
|
||||
|
||||
---
|
||||
|
||||
## 六、完成标准(验收条件)
|
||||
|
||||
本阶段完成定义为:
|
||||
|
||||
1. 可从开始游戏一路完成一个大关
|
||||
2. 节点之间流程无阻塞
|
||||
3. 组件可组装并生效
|
||||
4. 战斗可胜可负
|
||||
5. 商店可购买
|
||||
6. 不出现流程死锁
|
||||
7. 无严重崩溃或逻辑错误
|
||||
|
||||
只要流程跑通,即视为完成。
|
||||
|
||||
---
|
||||
|
||||
## 七、本阶段不评估指标
|
||||
|
||||
* 不评估留存
|
||||
* 不评估爽感强度
|
||||
* 不评估平衡性
|
||||
* 不评估变现能力
|
||||
@@ -0,0 +1,170 @@
|
||||
# MapEntity 设计规范(开发约束)
|
||||
|
||||
最后更新:2026-03-06
|
||||
|
||||
## 1. 目标与边界
|
||||
|
||||
`MapEntity` 现在是战斗地图域的编排层(orchestrator),目标是:
|
||||
- 对外暴露地图能力(格子查询、路径查询、建造操作入口)。
|
||||
- 在 Unity 生命周期中初始化/清理各子服务。
|
||||
- 承担输入与 UI 用例的连接,不承载具体业务算法细节。
|
||||
|
||||
`MapEntity` 不应再直接实现以下细节:
|
||||
- Tile 扫描与路径缓存算法。
|
||||
- 防御塔映射字典的增删改查细节。
|
||||
- 选中状态与攻击范围显示细节。
|
||||
- 鼠标拾取与 `CombatSelectFormUserData` 组装细节。
|
||||
- 战斗选择 UI 的库存快照解析、颜色映射与 Build 选项配置细节。
|
||||
|
||||
---
|
||||
|
||||
## 2. 模块划分(当前标准)
|
||||
|
||||
### 2.1 MapEntity(编排层)
|
||||
|
||||
文件:`Assets/GameMain/Scripts/Entity/EntityLogic/MapEntity.cs`
|
||||
|
||||
职责:
|
||||
- 生命周期编排:`OnInit / OnShow / OnUpdate / OnHide`
|
||||
- 子服务初始化与清理
|
||||
- UI 用例绑定(`CombatSelectFormUseCase`)
|
||||
- 将输入结果分发到选择器/建造器
|
||||
- 收集运行时上下文并委托给专用服务配置战斗选择 UI
|
||||
|
||||
### 2.2 MapTopologyService(地图拓扑层)
|
||||
|
||||
文件:`Assets/GameMain/Scripts/Scene/Map/MapTopologyService.cs`
|
||||
|
||||
职责:
|
||||
- 扫描 Tilemap,构建 `PathCells` / `FoundationCells`
|
||||
- 缓存 `Spawner -> 默认路径`
|
||||
- 提供路径查询:
|
||||
- `TryGetNearestPathCell`
|
||||
- `TryGetDefaultPathCells`
|
||||
- `TryFindPathCells`
|
||||
- `TryFindPathWorldPoints`
|
||||
|
||||
约束:
|
||||
- 只处理“地图拓扑与路径”,不处理经济、建塔、UI。
|
||||
|
||||
### 2.3 CombatSelectInputService(输入解析层)
|
||||
|
||||
文件:`Assets/GameMain/Scripts/Entity/EntityLogic/CombatSelectInputService.cs`
|
||||
|
||||
职责:
|
||||
- 鼠标屏幕坐标 -> 世界坐标
|
||||
- 判定点击对象类型(`None/Foundation/Tower`)
|
||||
- 组装 `CombatSelectFormUserData`
|
||||
|
||||
约束:
|
||||
- 只读上下文,不改变游戏状态。
|
||||
- Foundation/Tower 点击时,UI 定位由 Cell 中心决定(稳定定位)。
|
||||
|
||||
### 2.4 CombatSelectUseCaseConfigurator(战斗选择 UI 配置层)
|
||||
|
||||
文件:`Assets/GameMain/Scripts/Entity/EntityLogic/CombatSelectUseCaseConfigurator.cs`
|
||||
|
||||
职责:
|
||||
- 读取库存快照与参战塔快照
|
||||
- 构建组件映射与塔外观颜色
|
||||
- 配置 `CombatSelectFormUseCase` 的 Build/Upgrade/Destroy action 与显示参数
|
||||
- 缓存当前 Build 槽位对应的视觉信息,供建塔流程复用
|
||||
|
||||
约束:
|
||||
- 只负责 UI 选项配置与只读数据组装,不直接改变战斗状态。
|
||||
- 不处理鼠标输入、地图拓扑、塔实体生命周期。
|
||||
|
||||
### 2.5 TowerPlacementService(塔部署层)
|
||||
|
||||
当前文件:`Assets/GameMain/Scripts/Scene/Map/TowerPlacementService.cs`
|
||||
|
||||
职责:
|
||||
- 建造 / 升级 / 销毁(含升级失败回滚)
|
||||
- 维护塔映射状态:
|
||||
- `foundationCell -> towerEntityId`
|
||||
- `towerEntityId -> foundationCell`
|
||||
- `towerEntityId -> towerStats`
|
||||
- 提供整局清理接口
|
||||
|
||||
约束:
|
||||
- 仅处理塔生命周期与映射,不处理选中态和 UI。
|
||||
|
||||
### 2.6 TowerSelectionPresenter(选择展示层)
|
||||
|
||||
文件:`Assets/GameMain/Scripts/Scene/Map/TowerSelectionPresenter.cs`
|
||||
|
||||
职责:
|
||||
- 维护当前选中对象
|
||||
- 根据选中状态切换攻击范围显示(通过 `TowerEntity.SetAttackRangeVisible`)
|
||||
|
||||
约束:
|
||||
- 不做建造/升级/销毁。
|
||||
|
||||
---
|
||||
|
||||
## 3. 运行时主流程(简版)
|
||||
|
||||
1. `MapEntity.OnInit` 初始化并绑定 6 个对象:
|
||||
- `MapTopologyService`
|
||||
- `CombatSelectInputService`
|
||||
- `CombatSelectUseCaseConfigurator`
|
||||
- `TowerPlacementService`
|
||||
- `TowerSelectionPresenter`
|
||||
- `CombatSelectFormUseCase`
|
||||
2. `MapEntity.OnShow` 刷新地图拓扑,配置 UI action 与 Build 视觉数据。
|
||||
3. 每帧 `OnUpdate`:
|
||||
- 采集输入(InputService)
|
||||
- 更新选中对象(SelectionPresenter)
|
||||
- 打开/刷新 UI
|
||||
4. UI Build/Upgrade/Destroy action 回调:
|
||||
- 通过 PlacementService 改变塔状态
|
||||
- 通过 SelectionPresenter 同步选中和范围显示
|
||||
5. `OnHide`:
|
||||
- 关闭 UI
|
||||
- 隐藏并清理塔实体
|
||||
- 清理选择态与塔映射运行时状态
|
||||
- 清理拓扑缓存
|
||||
|
||||
---
|
||||
|
||||
## 4. 核心不变量(必须保持)
|
||||
|
||||
1. `MapEntity` 只编排,不承载业务细节实现。
|
||||
2. `TowerPlacementService` 是塔映射状态的唯一写入口。
|
||||
3. `MapTopologyService` 是 Path/Foundation 数据的唯一来源。
|
||||
4. “当前可见攻击范围”同一时刻最多一个塔。
|
||||
5. 清场顺序固定:先关闭 UI,再隐藏塔,再清空选择与映射,再清理拓扑缓存。
|
||||
|
||||
---
|
||||
|
||||
## 5. 扩展开发规范
|
||||
|
||||
### 5.1 新增地图规则(地形、禁建、动态阻挡)
|
||||
|
||||
优先改 `MapTopologyService`,不要直接改 `MapEntity`。
|
||||
|
||||
### 5.2 新增建造规则(费用、限制、回滚策略)
|
||||
|
||||
优先改 `TowerPlacementService`,不要在 `MapEntity` 写分支。
|
||||
|
||||
### 5.3 新增点击交互或 UI 定位策略
|
||||
|
||||
优先改 `CombatSelectInputService`。
|
||||
|
||||
### 5.4 新增 Build 选项展示、塔外观颜色或库存驱动 UI 配置
|
||||
|
||||
优先改 `CombatSelectUseCaseConfigurator`。
|
||||
|
||||
### 5.5 新增选中表现(特效、描边、信息面板联动)
|
||||
|
||||
优先改 `TowerSelectionPresenter`。
|
||||
|
||||
---
|
||||
|
||||
## 6. 代码变更检查清单(PR 自检)
|
||||
|
||||
1. 是否把新业务放进了对应服务,而不是 `MapEntity`?
|
||||
2. 是否破坏了“服务唯一写入口”不变量?
|
||||
3. Build/Upgrade 失败是否有完整回滚和金币返还?
|
||||
4. 清理路径是否覆盖了 `OnHide` 与重进地图场景?
|
||||
5. `dotnet build GeometryTD.sln` 是否通过?
|
||||
@@ -0,0 +1,238 @@
|
||||
# Tag System Design
|
||||
|
||||
最后更新:2026-03-13
|
||||
|
||||
> 目标:这是 GeometryTD 当前 Tag 系统的唯一正式口径。
|
||||
> 本文档只记录当前真实实现、当前边界与正式规则。
|
||||
> 长期扩展预案见 `docs/TagSystemRoadmap.md`;若两者冲突,以本文件为准。
|
||||
|
||||
## 1. 当前范围
|
||||
|
||||
M1 已完成 Tag 最小闭环:
|
||||
|
||||
- 组件实例 Tag 已统一生成,不再直接复制 `PossibleTag`
|
||||
- 塔级 Tag 已统一汇总为 `TagRuntimeData[]`
|
||||
- UI 展示已优先消费 `TagRuntimes`
|
||||
- 首发 7 个 Tag 已进入战斗实际生效
|
||||
|
||||
当前正式首发 7 个 Tag:
|
||||
|
||||
- `Fire`
|
||||
- `Ice`
|
||||
- `Crit`
|
||||
- `Execution`
|
||||
- `Shatter`
|
||||
- `Inferno`
|
||||
- `AbsoluteZero`
|
||||
|
||||
当前明确后移的 5 个 Tag:
|
||||
|
||||
- `BurnSpread`
|
||||
- `IgniteBurst`
|
||||
- `FreezeMask`
|
||||
- `Pierce`
|
||||
- `Overpenetrate`
|
||||
|
||||
当前不展开:
|
||||
|
||||
- 高级传播 / 多命中 / 击杀链式效果
|
||||
- 复杂流派激活矩阵
|
||||
- Tag 等级成长
|
||||
- `TagGroup` 运行时规则
|
||||
|
||||
## 2. 正式规则
|
||||
|
||||
1. Tag 在组件实例创建时随机;组塔阶段只汇总,不重新随机。
|
||||
2. 组件表的 `PossibleTag` 只表示候选池,不代表实例最终持有结果。
|
||||
3. 组塔后重复 Tag 不丢弃,而是转为塔级 `Stack`。
|
||||
4. 配置层正式采用 `Tag.txt + RarityTagBudget.txt + TagConfig.txt` 三表结构。
|
||||
5. `Tag.txt` 是 `IsImplemented` 的正式真相源;`TagConfig.txt` 只负责触发阶段、描述与运行时参数。
|
||||
6. 战斗中的 Tag 统一挂在 `AttackPayload -> HitContext -> TagEffectResolver` 链路上。
|
||||
7. 新逻辑应优先使用 `TagRuntimes`;`Tags` 只保留兼容投影职责。
|
||||
8. `TagGroup` 当前只作为展示元数据,不进入生成、汇总或战斗规则。
|
||||
|
||||
## 3. 配置与生成
|
||||
|
||||
### 3.1 三表职责
|
||||
|
||||
`Tag.txt`
|
||||
|
||||
- 负责基础字典与生成规则
|
||||
- 当前字段:`TagType`、`Name`、`TagGroup`、`MinRarity`、`Weight`、`IsImplemented`
|
||||
|
||||
`RarityTagBudget.txt`
|
||||
|
||||
- 负责按品质定义组件实例本次可抽取的 Tag 数量预算
|
||||
- 当前字段:`Rarity`、`MinCount`、`MaxCount`
|
||||
|
||||
`TagConfig.txt`
|
||||
|
||||
- 负责战斗与展示相关配置
|
||||
- 当前字段:`TriggerPhase`、`Description`、`ParamJson`
|
||||
|
||||
### 3.2 当前消费链
|
||||
|
||||
- `Tag.txt -> DRTag -> TagGenerationRuleRegistry`
|
||||
- 当前负责 `MinRarity`、`Weight`
|
||||
- `Tag.txt + TagConfig.txt -> TagDefinitionRegistry.ReloadFromRows(...)`
|
||||
- 当前负责 `IsImplemented`、`TriggerPhase`、`Description` 与正式运行时参数
|
||||
- `ProcedureMain -> GameEntry.TagRegistry.OnInit() -> TagRegistryComponent`
|
||||
- 当前在主流程进入时统一基于已加载数据表重建 Tag 定义层与生成规则层
|
||||
- `TagRegistryComponent` 对 `TagConfig`、`Tag`、`RarityTagBudget` 三张表采用 fail-fast 依赖约束;缺表时直接暴露初始化错误,不再静默跳过
|
||||
- `RarityTagBudget.txt -> DRRarityTagBudget -> RarityTagBudgetRuleRegistry`
|
||||
- 当前负责按品质读取 `MinCount / MaxCount`
|
||||
|
||||
### 3.3 运行时结构
|
||||
|
||||
- 组件实例保存 `TagType[]`
|
||||
- 塔实例保存 `TagRuntimeData[]`
|
||||
- 塔实例同时保留 `Tags` 作为兼容投影
|
||||
- 战斗载荷保存塔级 `TagRuntimeData[]`
|
||||
|
||||
```csharp
|
||||
public sealed class TagRuntimeData
|
||||
{
|
||||
public TagType TagType { get; set; }
|
||||
public int TotalStack { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 组件 Tag 生成
|
||||
|
||||
当前统一入口是 `ComponentTagGenerationService`,以下链路共用同一套规则:
|
||||
|
||||
- `InventorySeedUtility`
|
||||
- `InventoryGenerationComponent.BuildShopGoods(...)`
|
||||
- `InventoryGenerationComponent.ResolveEnemyDrop(...)`
|
||||
- `InventoryGenerationComponent.BuildRewardCandidates(...)`
|
||||
|
||||
当前流程:
|
||||
|
||||
1. 读取组件配置的 `PossibleTag`
|
||||
2. 读取 `Tag.txt` 中对应的生成规则
|
||||
3. 过滤掉 `None`、非法枚举、当前未首发支持的 Tag
|
||||
4. 过滤掉 `MinRarity > 当前组件品质` 的 Tag
|
||||
5. 根据 `RarityTagBudget.txt` 决定本次抽取数量
|
||||
6. 在候选池内按 `Weight` 抽取
|
||||
7. 单组件内不重复抽取同一 Tag
|
||||
8. 候选池不足时允许少于预算,不强行补满
|
||||
|
||||
### 3.5 可复现合同
|
||||
|
||||
Tag 随机结果的正式上下文为:
|
||||
|
||||
- `RunSeed`
|
||||
- `SourceType`
|
||||
- `ItemInstanceId`
|
||||
- `ConfigId`
|
||||
|
||||
当前运行时通过 `InventoryGenerationRandomContext + InventoryTagRandomContext` 统一承载上述字段:
|
||||
|
||||
- `InventoryGenerationRandomContext`
|
||||
- 统一承载 `runSeed + nodeSequenceIndex + sourceType + localOrdinal`
|
||||
- 统一派生产出链路自己的稳定随机流
|
||||
- 统一派生稳定的临时组件 `InstanceId`
|
||||
- `InventoryTagRandomContext`
|
||||
- 承载 Tag 生成所需的 `RunSeed / SourceType / ItemInstanceId / ConfigId`
|
||||
- 由 `InventoryGenerationRandomContext` 进一步派生
|
||||
|
||||
各来源构造口径:
|
||||
|
||||
- `Seed`:使用真实 `RunSeed` 与初始组件实例 Id
|
||||
- `Shop`:使用 `RunSeed + nodeSequenceIndex + goodsIndex + configId`
|
||||
- `Drop`:使用 `RunSeed + nodeSequenceIndex + dropOrdinal + configId`
|
||||
- `Reward`:使用 `RunSeed + nodeSequenceIndex + rewardOrdinal + configId`
|
||||
|
||||
## 4. 汇总、展示与战斗
|
||||
|
||||
### 4.1 汇总与展示
|
||||
|
||||
- 同一组件内不允许重复同一个 Tag
|
||||
- 不同组件之间允许重复
|
||||
- 组塔时不做重新随机
|
||||
- 汇总时按 `TagType` 分组并累加 `Stack`
|
||||
- 组件展示仍显示组件实例自己的 `Tags`
|
||||
- 塔展示优先显示 `TagRuntimes`
|
||||
- 若缺少 `TagRuntimes`,允许通过 `Tags` 回退构建兼容结果
|
||||
- 重复 Tag 以 `xN` 文本显示,例如 `Fire x2`
|
||||
- `TowerStatsData.Tags` 不是新的真相源,只用于兼容旧展示链路与旧数据
|
||||
|
||||
### 4.2 战斗上下文
|
||||
|
||||
`AttackPayload` 当前字段:
|
||||
|
||||
- `BaseDamage`
|
||||
- `AttackPropertyType`
|
||||
- `SourceEntityId`
|
||||
- `ProjectileEntityId`
|
||||
- `OriginPosition`
|
||||
- `TagRuntimes`
|
||||
|
||||
`HitContext` 当前字段:
|
||||
|
||||
- `AttackPayload`
|
||||
- `FinalDamage`
|
||||
- `IsCriticalHit`
|
||||
- `IsKilled`
|
||||
- `TargetEntityId`
|
||||
- `TargetPosition`
|
||||
- `TargetCurrentHealthBeforeHit`
|
||||
- `TargetCurrentHealthAfterHit`
|
||||
- `TargetMaxHealth`
|
||||
- `TargetMoveSpeedMultiplierBeforeHit`
|
||||
- `TargetStatusTagsBeforeHit`
|
||||
- `TargetStatusRuntime`
|
||||
- `CritRoll`
|
||||
- `StatusModifierContext`
|
||||
|
||||
`HitContext` 当前还提供:
|
||||
|
||||
- `HasTargetStatus(TagType)`
|
||||
- `HasSlowStatusBeforeHit`
|
||||
|
||||
### 4.3 分类与触发阶段
|
||||
|
||||
| 分类 | 说明 | 当前主触发阶段 |
|
||||
|------|------|----------------|
|
||||
| `Status` | 命中后在敌人身上形成可持续状态 | `OnAfterHit` |
|
||||
| `NumericModifier` | 命中前修正最终伤害 | `OnBeforeHit` |
|
||||
| `AttackShape` | 穿透、传播、爆炸等攻击形态变化 | `OnHit` / `OnKill` |
|
||||
| `StatusModifier` | 强化同次命中的状态类 Tag,但不独立生成敌人持有状态 | `OnAfterHit` |
|
||||
|
||||
### 4.4 当前已实现的首发 7 Tag
|
||||
|
||||
| Tag | 分类 | 配置阶段 | 当前真实行为 |
|
||||
|-----|------|----------|--------------|
|
||||
| `Fire` | `Status` | `OnAfterHit` | 命中后施加燃烧 DOT,且 `MaxEffectiveStack` 已进入基础层数结算 |
|
||||
| `Ice` | `Status` | `OnAfterHit` | 命中后施加减速 |
|
||||
| `Crit` | `NumericModifier` | `OnBeforeHit` | 按概率暴击并放大伤害 |
|
||||
| `Execution` | `NumericModifier` | `OnBeforeHit` | 对低血量目标增伤 |
|
||||
| `Shatter` | `NumericModifier` | `OnBeforeHit` | 对已减速目标增伤 |
|
||||
| `Inferno` | `StatusModifier` | `OnAfterHit` | 先由 resolver 解析为命中期修饰,再强化同次命中的 `Fire` 时长与伤害 |
|
||||
| `AbsoluteZero` | `StatusModifier` | `OnAfterHit` | 先由 resolver 解析为命中期修饰,再强化同次命中的 `Ice` 时长与减速强度 |
|
||||
|
||||
### 4.5 当前已后移的 5 Tag
|
||||
|
||||
| Tag | 分类 | 当前状态 |
|
||||
|-----|------|----------|
|
||||
| `BurnSpread` | `AttackShape` | 仅保留元数据、占位配置与占位路由,未实际生效 |
|
||||
| `IgniteBurst` | `AttackShape` | 仅保留元数据、占位配置与占位路由,未实际生效 |
|
||||
| `FreezeMask` | `AttackShape` | 仅保留元数据、占位配置与占位路由,未实际生效 |
|
||||
| `Pierce` | `AttackShape` | 仅保留元数据、占位配置与占位路由,未实际生效 |
|
||||
| `Overpenetrate` | `AttackShape` | 仅保留元数据、占位配置与占位路由,未实际生效 |
|
||||
|
||||
## 5. 当前运行时边界
|
||||
|
||||
- 数值类 Tag 在 `ResolveBeforeHit` 阶段生效
|
||||
- 状态类 Tag 通过 `EnemyTagStatusRuntime` 管理敌人持有状态
|
||||
- `StatusModifier` 已独立按 `OnAfterHit` 路由,并写入 `StatusModifierContext`
|
||||
- `Inferno` 与 `AbsoluteZero` 不生成敌人持有状态;没有 `Fire` / `Ice` 时不会单独产生效果
|
||||
- 后移 5 个攻击形态 Tag 的 `TriggerPhase` 当前正式口径为 `None`
|
||||
- 后移 5 个攻击形态 Tag 的 `ParamJson` 当前只视为占位说明,不是正式运行时字段
|
||||
|
||||
## 6. 非当前范围
|
||||
|
||||
- `BurnSpread`、`IgniteBurst`、`FreezeMask`、`Pierce`、`Overpenetrate` 的真实战斗实现
|
||||
- 更复杂的多 Tag 联动与流派激活矩阵
|
||||
- 冻结积累条、击杀爆炸传播链、多命中弹道系统
|
||||
- Tag 等级成长、TagGroup 运行时规则、额外 Tag 元数据扩展表
|
||||
@@ -0,0 +1,62 @@
|
||||
# Tag System Roadmap
|
||||
|
||||
最后更新:2026-03-12
|
||||
|
||||
> 目标:记录 Tag 系统的长期扩展预案。
|
||||
> 本文档不是当前实现真相源;若与 `docs/TagSystemDesign.md` 冲突,以 `docs/TagSystemDesign.md` 为准。
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
- `TagSystemDesign.md` 负责当前正式口径
|
||||
- 本文档只负责后续扩展方向
|
||||
- 这里出现的能力都不代表当前已经实现,也不代表已经排进最近一期开发
|
||||
|
||||
## 2. 可继续推进的方向
|
||||
|
||||
### 2.1 第二批攻击形态 Tag
|
||||
|
||||
后续可基于现有 `AttackPayload -> HitContext -> TagEffectResolver` 合同继续推进:
|
||||
|
||||
- `BurnSpread`
|
||||
- `IgniteBurst`
|
||||
- `FreezeMask`
|
||||
- `Pierce`
|
||||
- `Overpenetrate`
|
||||
|
||||
进入实现前提:
|
||||
|
||||
- 不破坏当前 `HitContext` 主干
|
||||
- 优先补上下文字段,不回退到散装参数扩展
|
||||
- 每个 Tag 进入真实战斗效果前,都要先明确它需要的命中信息与回归测试
|
||||
|
||||
### 2.2 更复杂的多 Tag 联动
|
||||
|
||||
可考虑的后续方向:
|
||||
|
||||
- 更深的状态连锁
|
||||
- 击杀传播或爆炸传播链
|
||||
- 多 Tag 组合触发的特殊行为
|
||||
|
||||
进入实现前提:
|
||||
|
||||
- 先定义联动的真相源与优先级
|
||||
- 不把展示元数据直接升级成运行时规则
|
||||
|
||||
### 2.3 成长与元数据扩展
|
||||
|
||||
可考虑的后续方向:
|
||||
|
||||
- Tag 等级成长
|
||||
- 更多 Tag 元数据扩展表
|
||||
- 运行时需要时再讨论 `TagGroup` 是否升级为规则输入
|
||||
|
||||
进入实现前提:
|
||||
|
||||
- 当前三表职责仍保持清晰
|
||||
- 新字段必须同时明确配置真相源、运行时消费者与展示口径
|
||||
|
||||
## 3. 当前默认约束
|
||||
|
||||
- 第二批 Tag 未进入真实战斗效果前,继续保持占位配置与占位路由
|
||||
- `TagGroup` 继续只作为展示元数据,不提前接入运行时
|
||||
- 新预案优先进入本文件,不回写到 `TagSystemDesign.md` 主干
|
||||
@@ -0,0 +1,182 @@
|
||||
# UI 五层架构设计规范(RawData / Controller / View / Context / UseCase)
|
||||
|
||||
## 1. 适用范围
|
||||
|
||||
- 适用目录:`Assets/GameMain/Scripts/UI/*`
|
||||
- 重点对象:采用五层拆分的 UI 模块(`MenuScene`、`GameScene`、`General` 下的分层 UI)
|
||||
- 本文不展开 Unity GameFramework 底层实现细节,仅约束项目内 UI 代码组织与协作方式
|
||||
|
||||
## 2. 架构总览
|
||||
|
||||
UI 模块采用“输入数据 -> 业务编排 -> 展示数据 -> 渲染表现”的分层方式,核心链路如下:
|
||||
|
||||
1. 外部流程(Procedure/GameState)创建并绑定 UseCase
|
||||
2. 通过 `GameEntry.UIRouter` 打开指定 UI
|
||||
3. Controller 从 UseCase 取 RawData,并转换为 Context
|
||||
4. View 使用 Context 渲染
|
||||
5. View 通过事件回传交互,Controller 处理后驱动 UseCase 更新,再刷新 View
|
||||
|
||||
简化关系图:
|
||||
|
||||
```text
|
||||
Procedure/GameState
|
||||
-> UIRouter
|
||||
-> Controller <-> UseCase
|
||||
-> Context -> View
|
||||
View --(CustomEvent)--> Controller
|
||||
```
|
||||
|
||||
## 3. 五层职责定义
|
||||
|
||||
### 3.1 RawData 层
|
||||
|
||||
职责:承载“业务原始数据”,作为 UseCase 到 Controller 的传输模型。
|
||||
|
||||
约束:
|
||||
|
||||
- 命名:`XXXFormRawData`
|
||||
- 只描述数据,不包含 UI 渲染行为
|
||||
- 可保留领域对象或数据表对象(例如 `DRLevelUpReward`、`WeaponBase`)
|
||||
- 不依赖具体 View 组件
|
||||
|
||||
参考:
|
||||
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/RawData/ShopFormRawData.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/RawData/LevelUpFormRawData.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/MenuScene/RawData/SelectRoleFormRawData.cs`
|
||||
|
||||
### 3.2 UseCase 层
|
||||
|
||||
职责:封装 UI 对应业务用例,负责业务规则、状态推进、数据生成。
|
||||
|
||||
约束:
|
||||
|
||||
- 实现 `IUIUseCase`
|
||||
- 命名:`XXXFormUseCase`
|
||||
- 对外提供 `CreateInitialModel / TryRefresh / Select / Confirm` 等语义化方法
|
||||
- 返回 RawData(或结果对象),不直接操作具体 View
|
||||
|
||||
参考:
|
||||
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/UseCase/ShopFormUseCase.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/UseCase/LevelUpFormUseCase.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/MenuScene/UseCase/SelectRoleFormUseCase.cs`
|
||||
|
||||
### 3.3 Controller 层
|
||||
|
||||
职责:UI 编排层,连接 UseCase 与 View,管理 UI 生命周期、事件订阅、数据转换。
|
||||
|
||||
约束:
|
||||
|
||||
- 继承 `UIFormControllerCommonBase<TContext, TForm>`
|
||||
- 命名:`XXXFormController`
|
||||
- 通过 `BindUseCase(IUIUseCase)` 注入用例并做类型校验
|
||||
- `OpenUI(object userData = null)` 支持:`Context`、`RawData`、`null`
|
||||
- 负责 RawData -> Context 的转换(常见 `BuildContext`)
|
||||
- 在 `SubscribeCustomEvents / UnsubscribeCustomEvents` 成对管理事件
|
||||
- 可做局部刷新(避免整窗重建)
|
||||
|
||||
参考:
|
||||
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/Controller/ShopFormController.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/Controller/LevelUpFormController.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/MenuScene/Controller/SelectRoleFormController.cs`
|
||||
|
||||
### 3.4 Context 层
|
||||
|
||||
职责:承载“可直接驱动 UI 展示”的上下文数据。
|
||||
|
||||
约束:
|
||||
|
||||
- 继承 `UIContext`
|
||||
- 命名:`XXXFormContext` 或 `XXXItemContext`
|
||||
- 字段以展示友好为目标(标题、描述、图标、稀有度、列表等)
|
||||
- 允许组合子 Context(例如列表区 + 条目)
|
||||
|
||||
参考:
|
||||
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/Context/ShopFormContext.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/Context/DisplayListAreaContext.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/MenuScene/Context/SelectRoleFormContext.cs`
|
||||
|
||||
### 3.5 View 层
|
||||
|
||||
职责:纯表现层,负责控件绑定、显示刷新、交互事件抛出。
|
||||
|
||||
约束:
|
||||
|
||||
- Form 类继承 `UGuiForm`,子组件通常继承 `MonoBehaviour`
|
||||
- 命名:`XXXForm` / `XXXItem` / `XXXArea`
|
||||
- 提供 `RefreshUI(Context)`、`OnInit(Context)`、`OnReset()` 等渲染入口
|
||||
- 用户交互通过 `GameEntry.Event.Fire(...)` 通知 Controller
|
||||
- 不承载业务规则(计算、流程推进、数据筛选应在 UseCase)
|
||||
|
||||
参考:
|
||||
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/View/ShopForm.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/GameScene/View/DisplayListArea.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Template/MenuScene/View/SelectRoleForm.cs`
|
||||
|
||||
## 4. 标准交互流程
|
||||
|
||||
### 4.1 初始化与绑定
|
||||
|
||||
1. Procedure/GameState 创建 UseCase
|
||||
2. 调用 `GameEntry.UIRouter.BindUIUseCase(UIFormType.X, useCase)`
|
||||
|
||||
### 4.2 打开 UI
|
||||
|
||||
1. 调用 `GameEntry.UIRouter.OpenUI(UIFormType.X)`
|
||||
2. Controller 从 UseCase 取 RawData(或接收外部 RawData/Context)
|
||||
3. Controller 构建 Context 后打开/刷新 Form
|
||||
4. View 在 `OnOpen` 中校验 Context 类型并执行 `RefreshUI`
|
||||
|
||||
### 4.3 用户交互到刷新
|
||||
|
||||
1. View 触发事件(如购买、刷新、选择)
|
||||
2. Controller 监听事件并调用 UseCase
|
||||
3. UseCase 返回新数据或操作结果
|
||||
4. Controller 更新 Context 并刷新全部或局部 UI
|
||||
|
||||
### 4.4 关闭 UI
|
||||
|
||||
1. 调用 `GameEntry.UIRouter.CloseUI(UIFormType.X)`
|
||||
2. Controller 解除事件订阅并关闭窗体
|
||||
3. View `OnClose` 清理本地状态
|
||||
|
||||
## 5. 目录与命名规范
|
||||
|
||||
- 目录:`UI/<SceneDomain>/RawData|UseCase|Controller|Context|View`
|
||||
- 五层同名前缀保持一致:`ShopForm*`、`LevelUpForm*`、`SelectRoleForm*`
|
||||
- 子组件上下文命名:`RoleItemContext`、`DisplayItemContext`、`LevelUpRewardItemContext`
|
||||
- 新增 UI Form 时优先建立完整五层;仅纯静态展示可降级为 View-only
|
||||
|
||||
## 6. 依赖方向约束
|
||||
|
||||
允许依赖:
|
||||
|
||||
- `UseCase -> RawData / 领域对象`
|
||||
- `Controller -> UseCase + RawData + Context + View + Event`
|
||||
- `View -> Context + Event`
|
||||
|
||||
禁止依赖:
|
||||
|
||||
- `View -> UseCase`
|
||||
- `View -> 领域状态修改`
|
||||
- `Context/RawData -> View`
|
||||
|
||||
## 7. 新增一个五层 UI 的落地步骤
|
||||
|
||||
1. 在目标场景目录创建 `RawData / UseCase / Context / Controller / View` 对应类型
|
||||
2. 在 UseCase 中实现模型创建与交互方法
|
||||
3. 在 Controller 中实现 `BindUseCase`、`OpenUI`、`BuildContext`、事件订阅
|
||||
4. 在 View 中实现 `RefreshUI` 和交互事件抛出
|
||||
5. 在对应 Procedure/GameState 里完成 UseCase 绑定与 Open/Close 调用
|
||||
6. 自测三条主链路:首次打开、交互刷新、关闭重开
|
||||
|
||||
## 8. 项目当前实践说明
|
||||
|
||||
- `ShopForm`、`LevelUpForm`、`SelectRoleForm` 是当前五层模式的主要样板
|
||||
- `DialogForm` 也有 Controller/Context/RawData,但 UseCase 为可选
|
||||
- `HudForm`、`StartMenuForm` 当前为轻用例场景,可不强制 UseCase
|
||||
- `SettingForm`、`AboutForm` 属于历史直连型 UI,不属于五层完整样板
|
||||
Reference in New Issue
Block a user