From 10232398800047ef1dd0176e5001fbe6570d4175 Mon Sep 17 00:00:00 2001 From: SepComet <202308010230@stu.csust.edu.cn> Date: Sun, 8 Mar 2026 18:08:13 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=81=E7=A7=BB=E6=B5=8B=E8=AF=95=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E5=BB=BA=E7=AB=8B=E4=B8=BB=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/GameMain/GeometryTD.Runtime.asmdef | 18 + .../GameMain/GeometryTD.Runtime.asmdef.meta | 7 + .../Scripts/Editor/GeometryTD.Editor.asmdef | 19 + .../Editor/GeometryTD.Editor.asmdef.meta | 7 + .../Scripts/Procedure/ProcedureMain.cs | 149 ++++++-- Assets/Tests.meta | 8 + Assets/Tests/EditMode.meta | 8 + .../EditMode/GeometryTD.Tests.EditMode.asmdef | 24 ++ .../GeometryTD.Tests.EditMode.asmdef.meta | 7 + .../EditMode}/RunStateTests.cs | 2 +- .../EditMode}/RunStateTests.cs.meta | 2 +- Assets/Tests/PlayMode.meta | 8 + .../PlayMode/GeometryTD.Tests.PlayMode.asmdef | 22 ++ .../GeometryTD.Tests.PlayMode.asmdef.meta | 7 + docs/CodeX-TODO.md | 334 +++++------------- docs/TODO.md | 36 +- 16 files changed, 351 insertions(+), 307 deletions(-) create mode 100644 Assets/GameMain/GeometryTD.Runtime.asmdef create mode 100644 Assets/GameMain/GeometryTD.Runtime.asmdef.meta create mode 100644 Assets/GameMain/Scripts/Editor/GeometryTD.Editor.asmdef create mode 100644 Assets/GameMain/Scripts/Editor/GeometryTD.Editor.asmdef.meta create mode 100644 Assets/Tests.meta create mode 100644 Assets/Tests/EditMode.meta create mode 100644 Assets/Tests/EditMode/GeometryTD.Tests.EditMode.asmdef create mode 100644 Assets/Tests/EditMode/GeometryTD.Tests.EditMode.asmdef.meta rename Assets/{GameMain/Tests/Editor => Tests/EditMode}/RunStateTests.cs (99%) rename Assets/{GameMain/Tests/Editor => Tests/EditMode}/RunStateTests.cs.meta (83%) create mode 100644 Assets/Tests/PlayMode.meta create mode 100644 Assets/Tests/PlayMode/GeometryTD.Tests.PlayMode.asmdef create mode 100644 Assets/Tests/PlayMode/GeometryTD.Tests.PlayMode.asmdef.meta diff --git a/Assets/GameMain/GeometryTD.Runtime.asmdef b/Assets/GameMain/GeometryTD.Runtime.asmdef new file mode 100644 index 0000000..3c004a3 --- /dev/null +++ b/Assets/GameMain/GeometryTD.Runtime.asmdef @@ -0,0 +1,18 @@ +{ + "name": "GeometryTD.Runtime", + "rootNamespace": "GeometryTD", + "references": [ + "UnityGameFramework.Runtime", + "Unity.InputSystem", + "Unity.TextMeshPro" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/Assets/GameMain/GeometryTD.Runtime.asmdef.meta b/Assets/GameMain/GeometryTD.Runtime.asmdef.meta new file mode 100644 index 0000000..945708c --- /dev/null +++ b/Assets/GameMain/GeometryTD.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e67bd2d1b65d48ce8120141996e55b2b +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Editor/GeometryTD.Editor.asmdef b/Assets/GameMain/Scripts/Editor/GeometryTD.Editor.asmdef new file mode 100644 index 0000000..2682f22 --- /dev/null +++ b/Assets/GameMain/Scripts/Editor/GeometryTD.Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "GeometryTD.Editor", + "rootNamespace": "GeometryTD.Editor", + "references": [ + "GeometryTD.Runtime", + "UnityGameFramework.Editor" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/Assets/GameMain/Scripts/Editor/GeometryTD.Editor.asmdef.meta b/Assets/GameMain/Scripts/Editor/GeometryTD.Editor.asmdef.meta new file mode 100644 index 0000000..6865576 --- /dev/null +++ b/Assets/GameMain/Scripts/Editor/GeometryTD.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 739d2e9771244fc8af6c8d8636eade79 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Procedure/ProcedureMain.cs b/Assets/GameMain/Scripts/Procedure/ProcedureMain.cs index e120ebc..0f0ddd5 100644 --- a/Assets/GameMain/Scripts/Procedure/ProcedureMain.cs +++ b/Assets/GameMain/Scripts/Procedure/ProcedureMain.cs @@ -8,6 +8,44 @@ using UnityGameFramework.Runtime; namespace GeometryTD.Procedure { + public enum ProcedureMainFlowPhase + { + Hub = 0, + NodeActive = 1, + RunCompletedPendingFinish = 2 + } + + public enum ProcedureMainRunAdvanceResult + { + NoChange = 0, + NodeFailed = 1, + AdvancedToNextNode = 2, + RunCompleted = 3 + } + + public static class ProcedureMainRunFlowService + { + public static ProcedureMainRunAdvanceResult TryAdvanceRun( + RunState runState, + bool succeeded, + BackpackInventoryData snapshot) + { + if (!RunStateAdvanceService.TryCompleteCurrentNode(runState, succeeded, snapshot)) + { + return ProcedureMainRunAdvanceResult.NoChange; + } + + if (runState != null && runState.IsCompleted) + { + return ProcedureMainRunAdvanceResult.RunCompleted; + } + + return succeeded + ? ProcedureMainRunAdvanceResult.AdvancedToNextNode + : ProcedureMainRunAdvanceResult.NodeFailed; + } + } + public class ProcedureMain : ProcedureBase { public override bool UseNativeDialog => false; @@ -15,6 +53,7 @@ namespace GeometryTD.Procedure private RepoFormUseCase _repoFormUseCase; private NodeMapFormUseCase _nodeMapFormUseCase; private RunState _currentRunState; + private ProcedureMainFlowPhase _flowPhase = ProcedureMainFlowPhase.Hub; #region FSM @@ -45,7 +84,7 @@ namespace GeometryTD.Procedure _nodeMapFormUseCase.SetRunState(_currentRunState); GameEntry.UIRouter.BindUIUseCase(UIFormType.NodeMapForm, _nodeMapFormUseCase); - OpenHubUI(); + EnterHubFlow(); } protected override void OnUpdate(IFsm procedureOwner, float elapseSeconds, @@ -69,6 +108,7 @@ namespace GeometryTD.Procedure _repoFormUseCase = null; _nodeMapFormUseCase = null; _currentRunState = null; + _flowPhase = ProcedureMainFlowPhase.Hub; base.OnLeave(procedureOwner, isShutdown); } @@ -117,8 +157,7 @@ namespace GeometryTD.Procedure args.NodeType, args.SequenceIndex); - GameEntry.UIRouter.CloseUI(UIFormType.NodeMapForm); - GameEntry.UIRouter.CloseUI(UIFormType.MainForm); + EnterNodeFlow(); } private void OnNodeComplete(object sender, GameEventArgs e) @@ -145,8 +184,7 @@ namespace GeometryTD.Procedure snapshot = GameEntry.PlayerInventory.GetInventorySnapshot(); } - AdvanceRunState(args.Succeeded, snapshot); - OpenHubUI(); + HandleRunAdvanceResult(ProcedureMainRunFlowService.TryAdvanceRun(_currentRunState, args.Succeeded, snapshot)); } private void OnCombatFailureReturn(object sender, GameEventArgs e) @@ -159,8 +197,7 @@ namespace GeometryTD.Procedure BackpackInventoryData snapshot = GameEntry.PlayerInventory != null ? GameEntry.PlayerInventory.GetInventorySnapshot() : null; - AdvanceRunState(false, snapshot); - OpenHubUI(); + HandleRunAdvanceResult(ProcedureMainRunFlowService.TryAdvanceRun(_currentRunState, false, snapshot)); } private void OnNodeMapNodeEnterRequested(object sender, GameEventArgs e) @@ -171,9 +208,15 @@ namespace GeometryTD.Procedure } RunNodeState currentNode = _currentRunState?.CurrentNode; - if (_currentRunState == null || !_currentRunState.CanEnterCurrentNode || currentNode == null) + if (_currentRunState == null || + _flowPhase != ProcedureMainFlowPhase.Hub || + !_currentRunState.CanEnterCurrentNode || + currentNode == null) { - Log.Warning("ProcedureMain.OnNodeMapNodeEnterRequested() ignored. Current run has no enterable node."); + Log.Warning( + "ProcedureMain.OnNodeMapNodeEnterRequested() ignored. FlowPhase={0}, HasEnterableNode={1}.", + _flowPhase, + _currentRunState != null && _currentRunState.CanEnterCurrentNode); return; } @@ -226,33 +269,30 @@ namespace GeometryTD.Procedure } } - private void AdvanceRunState(bool succeeded, BackpackInventoryData snapshot) + private void HandleRunAdvanceResult(ProcedureMainRunAdvanceResult result) { - if (_currentRunState == null) + switch (result) { - return; - } - - if (!RunStateAdvanceService.TryCompleteCurrentNode(_currentRunState, succeeded, snapshot)) - { - return; - } - - if (_currentRunState.IsCompleted) - { - Log.Info("ProcedureMain run completed. RunId={0}", _currentRunState.RunId); - return; - } - - RunNodeState nextNode = _currentRunState.CurrentNode; - if (nextNode != null) - { - Log.Info( - "ProcedureMain advanced run. RunId={0}, NextNodeType={1}, SequenceIndex={2}, LevelId={3}.", - _currentRunState.RunId, - nextNode.NodeType, - nextNode.SequenceIndex, - nextNode.LinkedLevelId); + case ProcedureMainRunAdvanceResult.NoChange: + return; + case ProcedureMainRunAdvanceResult.NodeFailed: + Log.Info( + "ProcedureMain current node failed. RunId={0}, NodeId={1}, NodeType={2}, SequenceIndex={3}.", + _currentRunState?.RunId, + _currentRunState?.CurrentNode?.NodeId ?? 0, + _currentRunState?.CurrentNode?.NodeType ?? RunNodeType.None, + _currentRunState?.CurrentNode?.SequenceIndex ?? -1); + EnterHubFlow(); + return; + case ProcedureMainRunAdvanceResult.AdvancedToNextNode: + LogNextNode(); + EnterHubFlow(); + return; + case ProcedureMainRunAdvanceResult.RunCompleted: + EnterRunCompletedPendingFinish(); + return; + default: + return; } } @@ -262,11 +302,48 @@ namespace GeometryTD.Procedure GameEntry.PlayerInventory.GetParticipantTowerSnapshot().Count > 0; } - private void OpenHubUI() + private void EnterHubFlow() { + _flowPhase = ProcedureMainFlowPhase.Hub; _nodeMapFormUseCase?.SetRunState(_currentRunState); GameEntry.UIRouter.OpenUI(UIFormType.NodeMapForm); GameEntry.UIRouter.OpenUI(UIFormType.MainForm); } + + private void EnterNodeFlow() + { + _flowPhase = ProcedureMainFlowPhase.NodeActive; + CloseHubUI(); + } + + private void EnterRunCompletedPendingFinish() + { + _flowPhase = ProcedureMainFlowPhase.RunCompletedPendingFinish; + _nodeMapFormUseCase?.SetRunState(_currentRunState); + CloseHubUI(); + Log.Info("ProcedureMain run completed. RunId={0}", _currentRunState?.RunId); + } + + private void CloseHubUI() + { + GameEntry.UIRouter.CloseUI(UIFormType.NodeMapForm); + GameEntry.UIRouter.CloseUI(UIFormType.MainForm); + } + + private void LogNextNode() + { + RunNodeState nextNode = _currentRunState?.CurrentNode; + if (nextNode == null) + { + return; + } + + Log.Info( + "ProcedureMain advanced run. RunId={0}, NextNodeType={1}, SequenceIndex={2}, LevelId={3}.", + _currentRunState.RunId, + nextNode.NodeType, + nextNode.SequenceIndex, + nextNode.LinkedLevelId); + } } -} \ No newline at end of file +} diff --git a/Assets/Tests.meta b/Assets/Tests.meta new file mode 100644 index 0000000..074eac3 --- /dev/null +++ b/Assets/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9f1bdc0fe72470fbe5ee26565921a4b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode.meta b/Assets/Tests/EditMode.meta new file mode 100644 index 0000000..192b17f --- /dev/null +++ b/Assets/Tests/EditMode.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 377f170c02c1478bafc8f641391a7887 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode/GeometryTD.Tests.EditMode.asmdef b/Assets/Tests/EditMode/GeometryTD.Tests.EditMode.asmdef new file mode 100644 index 0000000..b3f8154 --- /dev/null +++ b/Assets/Tests/EditMode/GeometryTD.Tests.EditMode.asmdef @@ -0,0 +1,24 @@ +{ + "name": "GeometryTD.Tests.EditMode", + "rootNamespace": "GeometryTD.Tests.EditMode", + "references": [ + "GeometryTD.Runtime", + "UnityGameFramework.Runtime" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "GameFramework.dll" + ], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false, + "optionalUnityReferences": [ + "TestAssemblies" + ] +} diff --git a/Assets/Tests/EditMode/GeometryTD.Tests.EditMode.asmdef.meta b/Assets/Tests/EditMode/GeometryTD.Tests.EditMode.asmdef.meta new file mode 100644 index 0000000..e9057e7 --- /dev/null +++ b/Assets/Tests/EditMode/GeometryTD.Tests.EditMode.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9d9745e0e8394cfa84739c027b399124 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Tests/Editor/RunStateTests.cs b/Assets/Tests/EditMode/RunStateTests.cs similarity index 99% rename from Assets/GameMain/Tests/Editor/RunStateTests.cs rename to Assets/Tests/EditMode/RunStateTests.cs index d6e38d3..2b73358 100644 --- a/Assets/GameMain/Tests/Editor/RunStateTests.cs +++ b/Assets/Tests/EditMode/RunStateTests.cs @@ -4,7 +4,7 @@ using GeometryTD.Definition; using GeometryTD.Procedure; using NUnit.Framework; -namespace GeometryTD.Tests.Editor +namespace GeometryTD.Tests.EditMode { public sealed class RunStateTests { diff --git a/Assets/GameMain/Tests/Editor/RunStateTests.cs.meta b/Assets/Tests/EditMode/RunStateTests.cs.meta similarity index 83% rename from Assets/GameMain/Tests/Editor/RunStateTests.cs.meta rename to Assets/Tests/EditMode/RunStateTests.cs.meta index 0f105cc..83b2139 100644 --- a/Assets/GameMain/Tests/Editor/RunStateTests.cs.meta +++ b/Assets/Tests/EditMode/RunStateTests.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 3d3e6fd8ec274118b59f66c6efc41405 +guid: e010ded52b54f984589333da57b3f393 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Tests/PlayMode.meta b/Assets/Tests/PlayMode.meta new file mode 100644 index 0000000..378bffe --- /dev/null +++ b/Assets/Tests/PlayMode.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0c4132be2aca4c2cae2e3d8dc89d020a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/PlayMode/GeometryTD.Tests.PlayMode.asmdef b/Assets/Tests/PlayMode/GeometryTD.Tests.PlayMode.asmdef new file mode 100644 index 0000000..096eed3 --- /dev/null +++ b/Assets/Tests/PlayMode/GeometryTD.Tests.PlayMode.asmdef @@ -0,0 +1,22 @@ +{ + "name": "GeometryTD.Tests.PlayMode", + "rootNamespace": "GeometryTD.Tests.PlayMode", + "references": [ + "GeometryTD.Runtime", + "UnityGameFramework.Runtime" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "GameFramework.dll" + ], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false, + "optionalUnityReferences": [ + "TestAssemblies" + ] +} diff --git a/Assets/Tests/PlayMode/GeometryTD.Tests.PlayMode.asmdef.meta b/Assets/Tests/PlayMode/GeometryTD.Tests.PlayMode.asmdef.meta new file mode 100644 index 0000000..2ca7e54 --- /dev/null +++ b/Assets/Tests/PlayMode/GeometryTD.Tests.PlayMode.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 10188d8fe2854dd4ace136e83d968aa7 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/docs/CodeX-TODO.md b/docs/CodeX-TODO.md index a964c8c..b9a8006 100644 --- a/docs/CodeX-TODO.md +++ b/docs/CodeX-TODO.md @@ -2,285 +2,111 @@ 最后更新:2026-03-08 -## 当前目标 +> 目标:基于当前仓库现状,为 `docs/TODO.md` 的 M1 收口补一份更可执行的补充顺序。 +> 原则:先收主流程,再补硬规则,最后统一文档与验收口径。 -按 `docs/TODO.md` 的 M1 目标推进最小可玩闭环,并以“能从开始游戏一路推进到 Boss 结算”为准检查当前实现。 +## 执行规则 -和上一版相比,仓库已经把 Run 相关基础件进一步接到了 `ProcedureMain`,因此这份清单不再把重点放在“有没有 Run 模型”,而是聚焦下面这几个真实阻塞项: +1. 优先完成会阻塞 M1 验收的内容,不提前展开 M2 深度功能。 +2. 每一项先收“流程可走通”,再收“规则完整”,最后再做表现层补齐。 +3. `ProcedureMain + NodeMapForm + PlayerInventory + CombatNode` 视为当前主链路,后续补充都围绕这条链路推进。 -- 已有 `ProcedureMenu + MenuForm -> ProcedureMain + NodeMapForm` 的主入口链路,正式节点面板骨架已经接入流程。 -- 固定 10 节点顺序已经开始驱动战斗 / 事件 / 商店入口,节点事件也已带上基础 Run 上下文字段。 -- 出战入口已有“至少有参战塔”的最小校验,但还没收口成严格的最终合法性约束。 -- 品质 / Tag / 耐久仍然停留在部分实现状态,尚未和 M1 范围完全对齐。 +## 阶段 S1 - 收口主流程 -## 当前已完成 +| 状态 | ID | 任务 | 交付物路径 | 验收标准 | +|-----|-------|--------------------------------|----------------------------------------------------------------------------|--------------------------| +| [x] | S1-01 | 统一梳理 M1 当前状态与文档口径 | `docs/CodeX-TODO.md`
`docs/TODO.md` | 当前实现、目标状态、未完成项三者口径一致 | +| [ ] | S1-02 | 收口 `ProcedureMain` 的 Run 推进主链路 | `Assets/GameMain/Scripts/Procedure/` | 从开始游戏到 Boss 结算可稳定走完整条链 | +| [ ] | S1-03 | 收口节点进入、完成、失败后的统一回流 | `Assets/GameMain/Scripts/Procedure/`
`Assets/GameMain/Scripts/Event/` | 战斗 / 事件 / 商店都能统一推进当前 Run | +| [ ] | S1-04 | 收口 Run 完成后的正式结束态 | `Assets/GameMain/Scripts/Procedure/`
`Assets/GameMain/Scripts/UI/Game/` | 10 节点完成后有明确的结束表现与收尾逻辑 | -### 1. 战斗主链路已经能独立跑通一场 +## S1-01 对齐结论 -- `CombatNodeComponent` 能加载关卡、阶段、出怪表并启动 `CombatScheduler`。 -- `CombatScheduler` 已具备加载地图、推进 phase、结算、失败返回等基础流程。 -- 战斗内已有基地血量、建塔消耗、敌人到家扣血、胜负结束等基础规则。 +### 当前实现 -关键文件: -- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs` -- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatScheduler.cs` -- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/` -- `Assets/GameMain/Scripts/Entity/EntityLogic/MapEntity.cs` +- `ProcedureMain + NodeMapForm` 已能创建固定 10 节点 Run,并驱动战斗 / 事件 / 商店三类节点的临时入口。 +- `RunState`、`FixedRunNodeSequenceBuilder`、`RunStateAdvanceService` 与对应 Editor 测试已存在,说明 Run 模型、固定序列、节点推进基础能力已经落地。 +- 战斗节点已有结算、奖励选择、失败返回;事件和商店节点也会发出 `NodeEnterEventArgs / NodeCompleteEventArgs`,但主流程仍属于“临时闭环”。 +- `P0-10 ~ P0-12` 不是纯空白: + - 出战前已有“参与区至少有 1 座塔”的最低门槛; + - 品质 / Tag 已在组装、商店、展示链路中分散使用; + - 耐久已有字段、展示与扣减入口。 -### 2. 战斗结算、掉落与奖励选择已有基础实现 +### M1 目标状态 -- 敌人被击败后已能发放 coin / gold / 组件掉落。 -- `CombatRunResourceStore` 维护局内资源与奖励背包快照。 -- 结算链已包含奖励计算、奖励选择 UI、FinishForm 返回等基础骨架。 +- M1 验收口径应以“从开始游戏到 Boss 节点结算结束,当前 Run 能稳定走完整条链”为准。 +- `NodeMapForm` 在 M1 里应被视为正式节点地图入口,而不是只靠临时面板勉强串流程。 +- 战斗 / 事件 / 商店都需要统一节点进入、完成、失败后的回流方式,避免每类节点各走一套。 +- 出战合法性需要从“至少有参战塔”收口为“满足完整三组件条件才可出战”。 -关键文件: -- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatRunResourceStore.cs` -- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/EnemyDrop/EnemyDropResolver.cs` -- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementService.cs` -- `Assets/GameMain/Scripts/UI/Combat/` +### 仍未完成 -### 3. 背包、参战区与组装基础能力已经存在 +- Run 完成后的正式结束态、Boss 后收尾表现、统一的主流程回流仍未收口。 +- 节点地图表现仍缺正式状态表达、说明文案与反馈,不应把这部分误记为已完成。 +- 品质 / Tag / 耐久在代码里已有局部实现,但还没有统一规则入口,因此仍应视为未收口项,而不是 M1 已完成项。 -- `PlayerInventoryComponent` 已支持库存快照、金币读写、参战塔名单、组装塔入口。 -- `RepoForm` 已能展示组件、塔、参战区和组装区。 -- `CombineArea` 已有三槽约束,只有枪口 / 轴承 / 底座齐备时才会发起组合请求。 -- `PlayerInventoryTowerAssemblyService` 已能基于三组件生成 `TowerItemData` 和 `TowerStatsData`。 +## 阶段 S2 - 收口节点地图表现 -关键文件: -- `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryComponent.cs` -- `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs` -- `Assets/GameMain/Scripts/UI/Game/View/RepoForm.cs` -- `Assets/GameMain/Scripts/UI/Game/View/CombineArea.cs` -- `Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.cs` +| 状态 | ID | 任务 | 交付物路径 | 验收标准 | +|-----|-------|--------------------------------|------------------------------------|------------------------| +| [ ] | S2-01 | 把 `NodeMapForm` 从临时面板收口成正式节点地图 | `Assets/GameMain/Scripts/UI/Game/` | 节点地图不再只是临时占位面板 | +| [ ] | S2-02 | 补齐节点状态、当前节点、完成态、Boss 节点表现 | `Assets/GameMain/Scripts/UI/Game/` | 玩家能一眼读懂当前 Run 进度 | +| [ ] | S2-03 | 补齐节点说明、反馈、回流提示 | `Assets/GameMain/Scripts/UI/Game/` | 节点点击、进入、完成、失败均有明确反馈 | +| [ ] | S2-04 | 统一节点地图与主 HUD / MainForm 的职责边界 | `Assets/GameMain/Scripts/UI/Game/` | Hub UI 职责清晰,不再重复表达同类信息 | -### 4. 事件节点已有可进入、可结算的基础实现 +## 阶段 S3 - 收口出战合法性 -- `EventNodeComponent` 能读取 `Event.txt`,解析事件选项并随机打开事件。 -- `EventForm` 的打开 / 关闭现已统一走 `UIRouter`,不再混用私有 controller。 -- 事件完成后会关闭 UI 并发出 `NodeCompleteEventArgs`。 +| 状态 | ID | 任务 | 交付物路径 | 验收标准 | +|-----|-------|------------------|--------------------------------------------------------------------------------------------------|--------------------| +| [ ] | S3-01 | 定义“合法参战塔”的最终判定口径 | `docs/CodeX-TODO.md`
`Assets/GameMain/Scripts/Definition/` | 流程层与 UI 层共用同一套判定口径 | +| [ ] | S3-02 | 收口组装区与参战区的合法性校验 | `Assets/GameMain/Scripts/UI/Game/`
`Assets/GameMain/Scripts/CustomComponent/PlayerInventory/` | 不合法塔不能进入参战区 | +| [ ] | S3-03 | 在战斗入口补齐最终出战校验 | `Assets/GameMain/Scripts/Procedure/` | 不满足完整条件时无法进入战斗节点 | +| [ ] | S3-04 | 给出 UI / 日志层明确反馈 | `Assets/GameMain/Scripts/UI/Game/`
`Assets/GameMain/Scripts/Procedure/` | 玩家知道为什么不能出战 | -关键文件: -- `Assets/GameMain/Scripts/CustomComponent/EventNodeComponent.cs` -- `Assets/GameMain/Scripts/UI/Game/UseCase/EventFormUseCase.cs` -- `Assets/GameMain/Scripts/UI/Game/Controller/EventFormController.cs` +## 阶段 S4 - 收口品质 / Tag 规则 -### 5. Run 模型和 10 节点固定序列已经落地到代码与测试 +| 状态 | ID | 任务 | 交付物路径 | 验收标准 | +|-----|-------|-------------------------|-----------------------------------------------------------------------------------------------------|----------------| +| [ ] | S4-01 | 先确定 M1 需要的品质 / Tag 规则边界 | `docs/CodeX-TODO.md`
`docs/TODO.md` | 文档先对齐,再落代码 | +| [ ] | S4-02 | 把品质计算整理成单一入口 | `Assets/GameMain/Scripts/Definition/`
`Assets/GameMain/Scripts/CustomComponent/PlayerInventory/` | 组装、掉落、商店使用一致结果 | +| [ ] | S4-03 | 把 Tag 生成与过滤整理成单一入口 | `Assets/GameMain/Scripts/Definition/`
`Assets/GameMain/Scripts/CustomComponent/PlayerInventory/` | Tag 结果可复现且可解释 | +| [ ] | S4-04 | 补齐与数据表规则的映射关系 | `Assets/GameMain/Scripts/DataTable/`
`Assets/GameMain/Scripts/Definition/` | 表字段不是只存在而未被消费 | -- 已有 `RunNodeType / RunNodeStatus / RunState / RunNodeState` 等运行时模型。 -- 已有 `RunStateFactory` 和 `RunStateAdvanceService` 处理节点创建、推进、失败和完成。 -- 已有 `FixedRunNodeSequenceBuilder`,Plain 主题下固定生成 10 节点,并且第 10 节点是 `BossCombat`。 -- 已有 Editor 测试覆盖 `RunState` 创建、节点推进、Boss 节点和固定 10 节点序列。 +## 阶段 S5 - 收口耐久规则 -关键文件: -- `Assets/GameMain/Scripts/Procedure/RunModel.cs` -- `Assets/GameMain/Scripts/Procedure/RunStateFactory.cs` -- `Assets/GameMain/Scripts/Procedure/RunStateAdvanceService.cs` -- `Assets/GameMain/Scripts/Procedure/FixedRunNodeSequenceBuilder.cs` -- `Assets/GameMain/Tests/Editor/RunStateTests.cs` +| 状态 | ID | 任务 | 交付物路径 | 验收标准 | +|-----|-------|-----------------------|-------------------------------------------------------------------------------------------------|----------------| +| [ ] | S5-01 | 先确认 M1 是否保留完整耐久闭环 | `docs/CodeX-TODO.md`
`docs/TODO.md` | 范围先明确,避免边做边改目标 | +| [ ] | S5-02 | 若保留,定义耐久对属性/出战资格的影响方式 | `Assets/GameMain/Scripts/Definition/`
`Assets/GameMain/Scripts/Entity/` | 规则口径清晰且可测试 | +| [ ] | S5-03 | 实现耐久扣减后的实际生效 | `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/`
`Assets/GameMain/Scripts/Entity/` | 耐久不再只是展示字段 | +| [ ] | S5-04 | 实现 `0` 耐久销毁或失效闭环 | `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/`
`Assets/GameMain/Scripts/UI/` | 归零后行为符合最终口径 | -### 6. 商店节点已经有最小可用实现 +## 阶段 S6 - 回归与文档收尾 -- `ShopNodeComponent.StartShop()` 已不再是空方法。 -- 新版 `ShopFormUseCase` 已能随机生成 4 个组件商品。 -- 已支持购买、扣金、把组件写回 `PlayerInventory`、退出商店。 +| 状态 | ID | 任务 | 交付物路径 | 验收标准 | +|-----|-------|-------------------------|---------------------------------------|--------------------------| +| [ ] | S6-01 | 补主链路回归测试 | `Assets/GameMain/Tests/` | Run 推进、节点回流、Boss 完成可回归验证 | +| [ ] | S6-02 | 补规则侧测试 | `Assets/GameMain/Tests/` | 合法性、品质、Tag、耐久关键公式可验证 | +| [ ] | S6-03 | 回写 `docs/TODO.md` 的真实状态 | `docs/TODO.md` | 文档状态与仓库现状一致 | +| [ ] | S6-04 | 清理临时描述、过期 TODO、命名偏差 | `docs/`
`Assets/GameMain/Scripts/` | 后续推进时不再被旧口径误导 | -关键文件: -- `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs` -- `Assets/GameMain/Scripts/UI/Shop/UseCase/ShopFormUseCase.cs` -- `Assets/GameMain/Scripts/UI/Shop/Controller/ShopFormController.cs` -- `Assets/GameMain/Scripts/UI/Shop/View/ShopForm.cs` +## 推荐执行顺序 -### 7. `NodeMapForm` 五层 UI 已经接入主流程 +1. 先做 `S1`,把主流程真正收成一条稳定可验收的链。 +2. 再做 `S2`,把当前临时 `NodeMapForm` 收成正式节点地图表现。 +3. 然后做 `S3`,补齐出战合法性,解决 `P0-10`。 +4. 再做 `S4`,统一品质 / Tag 的规则口径,解决 `P0-11`。 +5. 最后做 `S5`,决定耐久是完整收口还是同步缩范围,解决 `P0-12`。 +6. 全部完成后做 `S6`,补测试并同步文档状态。 -- 已新增 `NodeMapFormRawData / UseCase / Controller / Context / View` 和 `NodeItemContext / NodeItem`。 -- `ProcedureMain` 已不再打开 `TestMenuForm`,而是打开 `NodeMapForm` 作为 Hub 节点入口。 -- `NodeMapFormController` 会把 `NodeItem` 点击转换为 `NodeMapNodeEnterRequestedEventArgs`,再交给流程层决定是否进入节点。 -- `NodeItem` 的 `Icon` 已改成通过 `SpriteCacheComponent` 按资源名异步获取,`Bg` 负责表示节点状态。 +## 本周建议开工顺序 -关键文件: -- `Assets/GameMain/Scripts/UI/Game/RawData/NodeMapFormRawData.cs` -- `Assets/GameMain/Scripts/UI/Game/UseCase/NodeMapFormUseCase.cs` -- `Assets/GameMain/Scripts/UI/Game/Controller/NodeMapFormController.cs` -- `Assets/GameMain/Scripts/UI/Game/Context/NodeMapFormContext.cs` -- `Assets/GameMain/Scripts/UI/Game/Context/NodeItemContext.cs` -- `Assets/GameMain/Scripts/UI/Game/View/NodeMapForm.cs` -- `Assets/GameMain/Scripts/UI/Game/View/NodeItem.cs` -- `Assets/GameMain/Scripts/Event/Game/NodeMapNodeEnterRequestedEventArgs.cs` - -### 8. 菜单入口已切回独立 Menu 流程 - -- `ProcedureMenu` 当前只负责菜单入口,不再承载主流程 Hub 与节点推进逻辑。 -- `MenuForm` 已按五层结构补齐 `RawData / UseCase / Controller / Context / View`。 -- `Start` 按钮现在会驱动 `ProcedureMenu` 切场景,并在主场景加载完成后进入 `ProcedureMain`。 -- `Settings` 仍保留 `TODO` 占位,`Exit` 会直接退出游戏。 - -关键文件: -- `Assets/GameMain/Scripts/Procedure/ProcedureMenu.cs` -- `Assets/GameMain/Scripts/Procedure/Base/ProcedureChangeScene.cs` -- `Assets/GameMain/Scripts/UI/Menu/Controller/MenuFormController.cs` -- `Assets/GameMain/Scripts/UI/Menu/View/MenuForm.cs` - -## 当前未完成 - -### 1. Run 主流程已经形成基于 `NodeMapForm` 的临时闭环,但还没完全收口 - -- `ProcedureMain` 进入后会创建 Run,并打开 `MainForm + NodeMapForm`。 -- `NodeMapForm` 已经有五层结构,`NodeItem` 也能按当前 `RunState` 刷出 10 个节点。 -- 点击当前节点后,由 `NodeMapFormController` 发出 `NodeMapNodeEnterRequestedEventArgs`,再由 `ProcedureMain` 根据当前 `RunState.CurrentNode` 决定是否允许进入战斗 / 事件 / 商店。 -- 节点完成或战斗失败后,`ProcedureMain` 会推进 `RunState`,再重新打开 Hub UI。 -- 因此当前已经不是“测试菜单三选一”,而是“节点地图单入口”的临时版本。 - -当前缺口: -- `NodeMapForm` 已接入,但当前仍偏 MVP 骨架,缺节点连线、节点说明、Boss 特效等正式表现。 -- `NodeMapFormContext` 当前只提供基础进度和当前节点信息,还没有更完整的地图展示上下文。 -- Run 完成后的正式结算 / 收尾表现仍未建立。 - -关键文件: -- `Assets/GameMain/Scripts/Procedure/ProcedureMain.cs` -- `Assets/GameMain/Scripts/UI/Game/View/NodeMapForm.cs` -- `Assets/GameMain/Scripts/UI/Game/Controller/NodeMapFormController.cs` - -### 2. 固定 10 节点序列已开始驱动真实流程,但正式上下文系统仍不完整 - -- `FixedRunNodeSequenceBuilder` 已定义固定顺序和 Boss 终点。 -- `ProcedureMain` 已开始用当前 `RunNodeState.LinkedLevelId` 驱动战斗入口。 -- `EventNodeComponent` 和 `ShopNodeComponent` 已能进入并完成当前节点。 -- `EventNodeComponent` 的 UI 生命周期也已统一走 `UIRouter`。 -- `NodeEnter / NodeComplete` 已带 `runId / nodeId / nodeType / sequenceIndex` 等基础字段,`NodeComplete` 也会回传成功状态与库存快照。 -- 当前缺的不是“有没有上下文字段”,而是更系统化的节点追踪、展示与统一收口能力。 - -关键文件: -- `Assets/GameMain/Scripts/Procedure/FixedRunNodeSequenceBuilder.cs` -- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs` -- `Assets/GameMain/Scripts/CustomComponent/EventNodeComponent.cs` -- `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs` -- `Assets/GameMain/Scripts/Event/Game/NodeEnterEventArgs.cs` -- `Assets/GameMain/Scripts/Event/Game/NodeCompleteEventArgs.cs` - -### 3. 商店节点已纳入临时 Run 推进闭环,但回流目标仍是 MVP Hub - -- 现在可以单独打开商店、随机生成组件、购买并退出。 -- 商店结束后已能通过 `ProcedureMain` 推进当前 `RunState`。 -- 但退出后当前回流的是 `MainForm + NodeMapForm` 的 MVP 节点面板,而不是完整表现版地图。 - -关键文件: -- `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs` -- `Assets/GameMain/Scripts/UI/Shop/UseCase/ShopFormUseCase.cs` -- `Assets/GameMain/Scripts/Procedure/ProcedureMain.cs` - -### 4. 出战入口已有最小校验,但离最终验收还差一层 - -- `CombineArea` 已限制三槽必须齐备才能组塔。 -- `ProcedureMain` 已经补上“没有参战塔时禁止进入战斗节点”的最小校验。 -- 但这个校验目前仍是“有参战塔即可开战”,还不是“完整三组件合法塔”意义上的最终验收版本。 -- 这意味着当前还不满足 `P0-10` 里“未满足三组件时禁止出战”的验收要求。 - -关键文件: -- `Assets/GameMain/Scripts/UI/Game/View/CombineArea.cs` -- `Assets/GameMain/Scripts/Procedure/ProcedureMain.cs` -- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs` - -### 5. 品质 / 槽位 / Tag 规则仍只做了浅层版本 - -- 塔品质仍主要按三组件品质聚合得到。 -- `TowerItemData` 中没有真正落地“配件槽位数量”之类的核心字段。 -- Tag 仍主要来自组件自身配置或简单并集,未看到完整概率、数量、等级规则落地。 -- `DRTag` 已存在,但尚未形成明确的掉落 / 组装计算主链路。 -- `RarityType` 仍保留 `Red`,与部分 M1 文档描述未完全对齐。 - -关键文件: -- `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs` -- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/EnemyDrop/EnemyDropResolver.cs` -- `Assets/GameMain/Scripts/DataTable/DRTag.cs` -- `Assets/GameMain/Scripts/Definition/DataStruct/TowerItemData.cs` -- `Assets/GameMain/Scripts/Definition/Enum/RarityType.cs` - -### 6. 耐久仍停留在“展示 + 部分扣减”,没有形成真实生效闭环 - -- 当前组件耐久会显示在描述与 UI 上。 -- 低血通关后已存在扣耐久逻辑。 -- 但塔战斗属性是在组装时固化到 `TowerStatsData`,没有根据耐久实时衰减。 -- 组件耐久归 0 后也没有稳定的销毁 / 拆塔 / 失效闭环。 -- 因此 `P0-12` 的完整验收还没有达成。 - -关键文件: -- `Assets/GameMain/Scripts/Utility/ItemDescUtility.cs` -- `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerRosterService.cs` -- `Assets/GameMain/Scripts/Definition/DataStruct/TowerItemData.cs` -- `Assets/GameMain/Scripts/Definition/DataStruct/TowerCompItemData.cs` - -## 当前与 `docs/TODO.md` 的对照判断 - -结合静态代码检查,当前更接近下面这个状态: - -- `P0-04`:基础模型已完成,并已接入 `ProcedureMain + NodeMapForm` 的临时 Run 闭环。 -- `P0-05`:固定 10 节点序列已由 builder + `ProcedureMain + NodeMapForm` 驱动实际流程,基础事件上下文字段已接入,但缺更完整的地图表现层与正式上下文系统。 -- `P0-06`:节点进入、完成、失败后回 `NodeMapForm` 的临时闭环已存在,但正式地图表现与正式结算仍未完成。 -- `P0-10`:未完成。 -- `P0-11`:未完成。 -- `P0-12`:未完成。 - -换句话说,仓库已经不再是“还没有 Run 模型 / 10 节点 / 商店最小实现”的状态;真正的缺口是“这些能力已经接成 `NodeMapForm` 驱动的临时可跑版本,但还没收口成正式 M1 主流程表现层与上下文系统”。 - -## 推荐的后续执行顺序 - -1. 先把临时 Hub 升级成正式节点面板 - - 保留 `ProcedureMain` 持有 Run 的做法 - - 继续以 `NodeMapForm` 为基础补正式节点地图表现 - - 至少补上节点连线、Boss 视觉强调、当前节点说明和完成态反馈 - -2. 再补齐节点上下文的消费、追踪与统一推进 - - 继续沿用 `NodeEnterEventArgs` 和 `NodeCompleteEventArgs` 现有的 `runId / nodeId / nodeType / sequenceIndex` - - 节点完成后统一由流程层调用 `RunStateAdvanceService` - - 节点失败时明确是否停局、重试或返回菜单 - -3. 然后继续收口战斗关卡选择 - - 普通战斗和 Boss 战斗继续统一由当前 `RunNodeState.LinkedLevelId` 驱动 - - 去掉遗留的随机选关兜底路径,避免偏离 Run 顺序 - -4. 再补出战合法性校验 - - 没有完整参战塔时禁止进入战斗节点 - - 在 UI 和流程层都给出明确反馈 - -5. 最后再处理品质 / Tag / 耐久与文档对齐 - - 先确认 M1 是否真的保留红色品质和完整耐久 - - 再决定是补全实现,还是先缩范围并同步文档 - -## 当前做变更时要记住的约束 - -- 不要再把 Hub 退回 `TestMenuForm` 语义。 -- 不要把菜单入口和主流程 Hub 混回同一个 Procedure;保持 `ProcedureMenu -> ProcedureMain` 的职责边界。 -- 优先补“临时闭环 -> 正式节点 UI / 正式上下文”的收口,不要继续只加单点功能。 -- 商店已经接入 Run,下一步重点不是继续扩商店,而是把 Hub/UI 做正式。 -- 若 M1 最终不做完整耐久 / 红色品质,要先同步文档再改代码目标。 -- `PlayerInventory` 可以继续作为库存入口,但不要把整局 Run 状态直接混进库存对象里。 - -## 当前关键入口文件速查 - -- 流程入口: - - `Assets/GameMain/Scripts/Procedure/ProcedureMain.cs` -- Run 模型: - - `Assets/GameMain/Scripts/Procedure/RunModel.cs` - - `Assets/GameMain/Scripts/Procedure/RunStateFactory.cs` - - `Assets/GameMain/Scripts/Procedure/RunStateAdvanceService.cs` - - `Assets/GameMain/Scripts/Procedure/FixedRunNodeSequenceBuilder.cs` -- 当前 Hub / 节点入口: - - `Assets/GameMain/Scripts/UI/Game/Controller/NodeMapFormController.cs` - - `Assets/GameMain/Scripts/UI/Game/View/NodeMapForm.cs` -- 战斗节点 facade: - - `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs` -- 事件节点: - - `Assets/GameMain/Scripts/CustomComponent/EventNodeComponent.cs` -- 商店节点: - - `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs` -- 商店 UI: - - `Assets/GameMain/Scripts/UI/Shop/` -- 背包与组装: - - `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/` - - `Assets/GameMain/Scripts/UI/Game/` +1. 先收 `S1-02 ~ S1-04` +2. 再收 `S2-01 ~ S2-03` +3. 然后收 `S3-01 ~ S3-04` +4. 最后再决定 `S4` 和 `S5` 是完整实现还是同步缩范围 ## 备注 -- 这份清单基于 2026-03-08 的静态代码检查更新。 -- 本次已修正上一版中“Run 模型不存在”“10 节点未实现”“商店节点基本未实现”等过期判断。 -- 当前最值得优先推进的是:`NodeMapForm 继续收口表现层 -> 节点事件带上下文 -> 战斗按节点关卡进入 -> 出战校验`。 +- 这份清单只规划补充顺序,不试图在文档里展开所有实现细节。 +- 如果后续确认 M1 不做完整品质 / Tag / 耐久闭环,应先改 `docs/TODO.md`,再调整本清单。 diff --git a/docs/TODO.md b/docs/TODO.md index 2a393ac..d737cc0 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -9,22 +9,28 @@ 2. 每项任务必须同时满足“交付物路径”和“验收标准”才可打勾。 3. 数据驱动优先:数值、掉落、商店、事件都优先落到 `DataTables`。 +## M1 当前口径(2026-03-08) + +- 当前仓库已经具备 `ProcedureMain + NodeMapForm + CombatNode + EventNode + ShopNode` 的临时 Run 闭环,可以创建固定 10 节点流程并推进到各类节点入口。 +- M1 现在的真实缺口,不是“有没有 Run 雏形”,而是“能否稳定完成 Boss 后收尾、统一节点回流、把节点地图与合法出战规则收口成正式口径”。 +- `P0-10 ~ P0-12` 在代码里都已有局部实现,因此文档里统一按“部分完成但未收口”处理;只有满足最终验收标准后才可改成完成。 + ## 里程碑 M1(P0)- 最小可玩闭环 -| 状态 | ID | 任务 | 交付物路径 | 验收标准 | -|-----|-------|-------------------------------------|----------------------------------------------------------------------------------------|---------------------------| -| [x] | P0-01 | 冻结 MVP 范围(只保留:战斗节点/事件节点/商店节点/节点后组装) | `docs/MVP-Scope.md` | 明确“做/不做”清单,团队评审通过 | -| [x] | P0-02 | 补齐数据表:组件、配件、敌人、波次、节点、事件、商店商品 | `Assets/GameMain/DataTables/*.txt` | 游戏启动可无报错加载全部新增表 | -| [x] | P0-03 | 新增/完善 DataRow 解析类 | `Assets/GameMain/Scripts/DataTable/*.cs` | 每个新增表都有对应 DR 类并成功解析 | -| [~] | P0-04 | 建立单局 Run 状态模型(金币、生命、库存、当前节点) | `Assets/GameMain/Scripts/Procedure/` | 已有 `RunState` / 推进模型 / 测试,并已接入 `ProcedureMain + NodeMapForm` 的临时 Run 闭环 | -| [~] | P0-05 | 实现 10 节点地图生成(最后节点固定 Boss) | `Assets/GameMain/Scripts/Procedure/`
`Assets/GameMain/Scripts/Scene/` | 已有固定 10 节点序列 builder 与测试,且已由 `NodeMapForm` 驱动节点入口,但节点事件上下文与地图表现层仍未完成 | +| 状态 | ID | 任务 | 交付物路径 | 验收标准 | +|-----|-------|-------------------------------------|----------------------------------------------------------------------------------------|--------------------------------------------------------------------------| +| [x] | P0-01 | 冻结 MVP 范围(只保留:战斗节点/事件节点/商店节点/节点后组装) | `docs/MVP-Scope.md` | 明确“做/不做”清单,团队评审通过 | +| [x] | P0-02 | 补齐数据表:组件、配件、敌人、波次、节点、事件、商店商品 | `Assets/GameMain/DataTables/*.txt` | 游戏启动可无报错加载全部新增表 | +| [x] | P0-03 | 新增/完善 DataRow 解析类 | `Assets/GameMain/Scripts/DataTable/*.cs` | 每个新增表都有对应 DR 类并成功解析 | +| [~] | P0-04 | 建立单局 Run 状态模型(金币、生命、库存、当前节点) | `Assets/GameMain/Scripts/Procedure/` | 已有 `RunState` / 推进模型 / 测试,并已接入 `ProcedureMain + NodeMapForm` 的临时 Run 闭环 | +| [~] | P0-05 | 实现 10 节点地图生成(最后节点固定 Boss) | `Assets/GameMain/Scripts/Procedure/`
`Assets/GameMain/Scripts/Scene/` | 已有固定 10 节点序列 builder 与测试,且已由 `NodeMapForm` 驱动节点入口,但节点事件上下文与地图表现层仍未完成 | | [~] | P0-06 | 实现节点选择与跳转流程(战斗/事件/商店) | `Assets/GameMain/Scripts/Procedure/` | `ProcedureMain + NodeMapForm` 的临时闭环已可推进战斗/事件/商店,但仍缺完整地图表现、正式结算收尾与节点上下文回流 | -| [x] | P0-07 | 战斗节点基础玩法:放置塔、出怪、基地扣血、胜负判定 | `Assets/GameMain/Scripts/Entity/`
`Assets/GameMain/Scripts/Scene/` | 可完整打一场并得到胜利/失败结果 | -| [x] | P0-08 | 胜利波次与结算规则(100/80/50/<50) | `Assets/GameMain/Scripts/Procedure/` | 结算奖励与惩罚严格匹配设计文档 | -| [x] | P0-09 | 敌人掉落与关卡奖励(组件/配件/金币) | `Assets/GameMain/Scripts/Entity/` | 战斗结束能发放掉落并写入库存 | -| [ ] | P0-10 | 节点后组装:枪口/轴承/底座三组件约束 | `Assets/GameMain/Scripts/Entity/`
`Assets/GameMain/Scripts/UI/Templates/GameScene/` | 未满足三组件时禁止出战 | -| [ ] | P0-11 | 品质/槽位/Tag 计算落地(白绿蓝紫红) | `Assets/GameMain/Scripts/Definition/`
`Assets/GameMain/Scripts/Entity/` | 计算结果可复现并与规则一致 | -| [ ] | P0-12 | 组件/配件耐久生效与 0 耐久销毁 | `Assets/GameMain/Scripts/Entity/` | 耐久影响属性,归零后物品移除 | +| [x] | P0-07 | 战斗节点基础玩法:放置塔、出怪、基地扣血、胜负判定 | `Assets/GameMain/Scripts/Entity/`
`Assets/GameMain/Scripts/Scene/` | 可完整打一场并得到胜利/失败结果 | +| [x] | P0-08 | 胜利波次与结算规则(100/80/50/<50) | `Assets/GameMain/Scripts/Procedure/` | 结算奖励与惩罚严格匹配设计文档 | +| [x] | P0-09 | 敌人掉落与关卡奖励(组件/配件/金币) | `Assets/GameMain/Scripts/Entity/` | 战斗结束能发放掉落并写入库存 | +| [~] | P0-10 | 节点后组装:枪口/轴承/底座三组件约束 | `Assets/GameMain/Scripts/Entity/`
`Assets/GameMain/Scripts/UI/Templates/GameScene/` | 当前只校验“参与区至少有 1 座塔”,尚未收口为“三组件完整合法参战” | +| [~] | P0-11 | 品质/槽位/Tag 计算落地(白绿蓝紫红) | `Assets/GameMain/Scripts/Definition/`
`Assets/GameMain/Scripts/Entity/` | 组装、商店、展示链路已有局部品质 / Tag 赋值,但还没有单一、可复现、跨流程共用的规则入口 | +| [~] | P0-12 | 组件/配件耐久生效与 0 耐久销毁 | `Assets/GameMain/Scripts/Entity/` | 已有耐久字段、展示与扣减入口,但尚未影响属性 / 出战资格,也未形成 `0` 耐久移除或失效闭环 | ## 里程碑 M2(P1)- 核心深度 @@ -55,9 +61,9 @@ ## 本周建议开工顺序 -1. 先把 `P0-04` ~ `P0-06` 从“`NodeMapForm` 临时闭环”收口成正式节点地图表现,并补齐节点事件上下文 +1. 先把 `P0-04` ~ `P0-06` 从“`NodeMapForm` 临时闭环”收口成正式主流程,并补齐 Boss 完成后的结束态与节点回流口径 2. 完成 `P0-10`(把“至少有参战塔”提升为“满足完整合法参战条件才能出战”) -3. 再处理 `P0-11` ~ `P0-12`(品质 / Tag / 耐久是否纳入 M1 需先统一范围) +3. 再处理 `P0-11` ~ `P0-12`(先统一 M1 范围,再决定是完整收口还是同步缩范围) ## 设计优化 Backlog(新增)