From c240d7322ec850473e2565201b2b53762a93d7d1 Mon Sep 17 00:00:00 2001 From: chen Date: Tue, 1 Sep 2026 22:30:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9EP1=E6=A8=A1=E5=9D=97=E6=8B=86?= =?UTF-8?q?=E5=88=86=E4=B8=8E=E5=BC=9F=E5=AD=90=E7=AE=A1=E7=90=86=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/P1模块拆分.md | 141 ++++++++++++++++++++++++++++++++++++++++++++++ doc/弟子管理.md | 85 ++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 doc/P1模块拆分.md create mode 100644 doc/弟子管理.md diff --git a/doc/P1模块拆分.md b/doc/P1模块拆分.md new file mode 100644 index 0000000..3ac00d5 --- /dev/null +++ b/doc/P1模块拆分.md @@ -0,0 +1,141 @@ +# P1 模块拆分 + +P1 目标:种田 → 交货 → 灵石 → 修炼 → 更强的种田 循环跑通。本文档定义 P1 的模块划分、职责、依赖、通信方式与测试方式。详见 `doc/Roadmap.md`、`doc/弟子管理.md`。 + +## 1. 架构原则:前后端分离 + +- **后端**:Manager 脚本(持有数据和逻辑),不依赖 UI。 +- **前端**:UI 场景(只管显示),不持有任何游戏状态,所有数据从后端读取。 +- **通信规则**: + - UI → 后端:调用公开方法(如 `refine_pill()`) + - 后端 → UI:信号推送状态变化(如 `balance_changed`) +- **好处**:后端可脱离 UI 单独测试;UI 可随意更换;存档只序列化 Manager 状态。 +- **不抽象过度**:Manager 脚本本身就是后端,Godot 信号就是通信机制,不引入额外 Service/Interface 层。 + +## 2. 文件结构总览 + +``` +src/ +├── Core/ # 已有,不改 +│ ├── GameState.gd +│ ├── TimeSystem.gd +│ ├── SaveSystem.gd +│ └── MainGame.gd # 挂载所有 P1 管理器 +│ +├── Data/ +│ └── Models/ # 数据模型(纯 RefCounted,无逻辑) +│ ├── Disciple.gd # 弟子数据(见 弟子管理.md) +│ ├── FieldData.gd # 灵田数据 +│ ├── PillRecipeData.gd # 丹方数据 +│ └── OrderData.gd # 订单数据 +│ +├── Character/ +│ ├── DiscipleManager.gd # 弟子管理器 +│ └── test_disciple.tscn # 独立测试场景 +│ +├── Production/ +│ ├── FieldManager.gd # 灵田管理器 +│ ├── AlchemyManager.gd # 炼丹管理器 +│ ├── test_field.tscn # 灵田测试 +│ └── test_alchemy.tscn # 炼丹测试 +│ +├── Sect/ +│ ├── InventoryManager.gd # 库存管理(灵药/丹药/凡粮) +│ ├── EconomyManager.gd # 经济系统(灵石收支) +│ ├── OrderManager.gd # 订单管理 +│ ├── FoodManager.gd # 口粮管理 +│ ├── test_economy.tscn # 经济测试 +│ ├── test_order.tscn # 订单测试 +│ └── test_food.tscn # 口粮测试 +│ +└── UI/ + └── HUD/ + └── MainSceneHud.gd # 已有,P1 加灵石显示(前端接入) +``` + +## 3. 模块职责与依赖 + +| 模块 | 文件 | 职责 | 依赖 | 信号 | +| --- | --- | --- | --- | --- | +| 弟子数据 | `Data/Models/Disciple.gd` | 弟子属性(境界/技艺/忠诚/修为) | 无 | — | +| 灵田数据 | `Data/Models/FieldData.gd` | 内外田、作物、生长周期、品质 | 无 | — | +| 丹方数据 | `Data/Models/PillRecipeData.gd` | 材料→成品、技艺要求、品质系数 | 无 | — | +| 订单数据 | `Data/Models/OrderData.gd` | 客户、物品、数量、品质要求、期限、奖励 | 无 | — | +| 弟子管理 | `Character/DiscipleManager.gd` | CRUD + 修炼结算 | Disciple | `disciple_added/removed/attr_changed` | +| 灵田管理 | `Production/FieldManager.gd` | 种植/生长/收获 → 库存 | FieldData, InventoryManager | `field_harvested` | +| 炼丹管理 | `Production/AlchemyManager.gd` | 消耗材料产出丹药 | PillRecipeData, InventoryManager | `pill_refined` | +| 库存管理 | `Sect/InventoryManager.gd` | 物品存取(灵药/丹药/凡粮) | 无 | `inventory_changed` | +| 口粮管理 | `Sect/FoodManager.gd` | 凡人弟子口粮消耗 | DiscipleManager, InventoryManager | `food_shortage` | +| 订单管理 | `Sect/OrderManager.gd` | 订单生成/交货/过期 | OrderData, InventoryManager, EconomyManager | `order_fulfilled/expired` | +| 经济系统 | `Sect/EconomyManager.gd` | 灵石收支、余额 | 无 | `balance_changed` | + +## 4. 信号流(核心循环) + +``` +TimeSystem.advance_month() + → month_passed + → FieldManager.settle_month() [灵田生长/收获入库存] + → DiscipleManager.settle_month() [修炼消耗灵石、修为增长] + → FoodManager.settle_month() [口粮消耗,凡人弟子数×口粮] + → OrderManager.settle_month() [订单过期检查] + → EconomyManager.settle_month() [香火供奉等固定收入] + +玩家操作: + FieldManager.plant_field() → field_harvested (收获灵药) → InventoryManager + AlchemyManager.refine() → pill_refined (炼丹成功) → InventoryManager + OrderManager.fulfill() → order_fulfilled (交货) → EconomyManager 加灵石 +``` + +- 各管理器暴露 `settle_month()`,由 MainGame 连接 `month_passed` 按顺序调用;管理器自身不依赖 TimeSystem autoload,测试时可直接调用。 + +## 5. 依赖注入方式 + +管理器不直接引用 autoload,通过 `setup()` 注入依赖: + +```gdscript +# MainGame._ready() 中: +economy_manager.setup() +field_manager.setup(inventory_manager) +alchemy_manager.setup(inventory_manager) +food_manager.setup(disciple_manager, inventory_manager) +order_manager.setup(inventory_manager, economy_manager) +``` + +好处:测试场景只需注入 Mock 依赖,模块可独立运行。 + +## 6. 独立测试方式 + +每个模块对应一个测试场景(`test_xxx.tscn`): + +1. 实例化被测管理器 + 注入 Mock 依赖 +2. `_ready()` 中自动执行用例 +3. 用例覆盖:正常流程、边界条件(余额不足/库存不足/过期)、信号是否正确发出 +4. `print` 输出 PASS/FAIL,编辑器直接 F6 运行该场景验证 + +## 7. 开发顺序(依赖链自底向上) + +| 步骤 | 模块 | 理由 | +| --- | --- | --- | +| 1 | 4 个数据模型(Disciple/FieldData/PillRecipeData/OrderData) | 无依赖,纯数据 | +| 2 | InventoryManager | 无依赖,被 3 个模块使用 | +| 3 | DiscipleManager + 测试 | 只依赖数据 | +| 4 | FieldManager + 测试 | 依赖库存 | +| 5 | AlchemyManager + 测试 | 依赖库存 | +| 6 | FoodManager + 测试 | 依赖弟子+库存 | +| 7 | OrderManager + 测试 | 依赖库存+经济 | +| 8 | EconomyManager + 测试 | 无依赖(独立收支) | +| 9 | MainGame 集成所有管理器 | 组装 | +| 10 | HUD 灵石显示(前端接入) | UI 层 | + +每完成一步都能单独测试验证,不会出现"全做完才能跑"的情况。 + +## 8. P1 简化决策 + +| 完整愿景 | P1 取舍 | 后续 | +| --- | --- | --- | +| 忠诚度系统 | 仅存字段,不参与结算 | P2 启用 | +| 收徒 | 不做,初始弟子固定 | P2 | +| 随机委托 | 不做 | P2 | +| 香火供奉 | 简化为每月固定小额收入 | P2 完整化 | +| 灵田品质 | 收获时按种植者技艺定品质,无随机 | 可加随机 | +| 炼丹失败 | 材料足够即成功,品质随技艺浮动 | 可加失败率 | diff --git a/doc/弟子管理.md b/doc/弟子管理.md new file mode 100644 index 0000000..a7d603d --- /dev/null +++ b/doc/弟子管理.md @@ -0,0 +1,85 @@ +# 弟子管理模块设计 + +模块位置:P1 核心循环(见 `doc/Roadmap.md`)。本文档描述弟子数据模型与弟子管理器的设计。 + +## 1. 结构:数据类 + 管理器 + +弟子模块拆分为两层: + +| 层 | 文件 | 类型 | 职责 | +| --- | --- | --- | --- | +| 弟子数据类 | `src/Data/Models/Disciple.gd` | RefCounted | 持有弟子的所有信息,纯数据,无逻辑 | +| 弟子管理器 | `src/Character/DiscipleManager.gd` | Node | 添加、删除、查询、修改弟子属性 + 领域操作(修炼结算) | + +## 2. 设计模式 + +| 角色 | 模式 | 说明 | +| --- | --- | --- | +| 弟子数据类 | 纯数据模型 | RefCounted,运行时可变数据,不依赖场景树,可脱离场景单测 | +| 弟子管理器 | 仓储模式(Repository) | CRUD + 查询的集中入口,是弟子数据的唯一管理者 | +| 变化通知 | 观察者模式(Observer) | 管理器发信号,UI/其他系统订阅实时刷新 | +| 弟子创建 | 工厂方法(Factory) | 初始弟子/收徒的创建逻辑收在管理器内 | + +**明确不用的方案**: + +- 不用 ECS:弟子属性固定(境界/技艺/忠诚…),无动态组件需求,是过度设计。 +- 不用 Resource/.tres:弟子是运行时可变数据,RefCounted 类最轻量,不走序列化资源。 +- 不把所有逻辑塞进数据类:领域操作归管理器,保证修改只有单一入口,信号好通知,测试好做。 + +## 3. Disciple 数据类(RefCounted,纯数据) + +```gdscript +var name: String +var is_mortal: bool # 凡人弟子 +var realm_level: int = 1 # 境界 1-9 +var cultivation_skill: int = 1 # 种植技艺 1-10 +var alchemy_skill: int = 1 # 炼丹技艺 1-10 +var loyalty: int = 50 # 忠诚 0-100(P1 仅存字段) +var cultivation_exp: int = 0 # 修为进度 +``` + +只读派生(不存储,由属性计算): + +- `monthly_cost() -> int`:每月修炼灵石消耗(凡人弟子为 0) +- `realm_name() -> String`:境界显示名(凡人 / 炼气X层…) +- `exp_to_next() -> int`:升到下一境界所需修为 + +## 4. DiscipleManager 管理器(Node,仓储) + +```gdscript +signal disciple_added(disciple) +signal disciple_removed(disciple) +signal disciple_attr_changed(disciple, attr_name, old_value, new_value) + +func add_disciple(d) -> void +func remove_disciple(d) -> void +func get_disciple(id) -> Disciple +func get_all() -> Array[Disciple] +func get_by_realm(level) -> Array[Disciple] +func count_mortals() -> int +func set_attr(d, attr, value) -> void # 修改唯一入口,内部发信号 +func settle_month() -> void # 修炼结算(领域操作) +func to_dict() -> Dictionary # 存档网关 +func load_from_dict(d) -> void +``` + +## 5. 关键设计决策 + +1. **修改只走管理器**——`set_attr()` 是唯一变更入口,内部统一发 `disciple_attr_changed`。UI 订阅它实时刷新,也为以后忠诚度/事件系统留监听点。 +2. **查询返回引用**——性能好(P1 规模无碍),但禁止外部直接写属性;要写必须走管理器。 +3. **管理器是 Node,数据类是 RefCounted**——管理器可挂 MainGame/测试场景;数据类脱离场景树也能单测。 +4. **领域操作在管理器**——`settle_month()`(修炼消耗灵石、增加修为、境界提升)归管理器,数据类不碰业务逻辑。 +5. **存档网关(Unit of Work)**——序列化/恢复只经过管理器 `to_dict()/load_from_dict()`,为 SaveSystem 注册预留。 + +## 6. 测试方式 + +独立测试场景 `src/Character/test_disciple.tscn`: + +1. 实例化 DiscipleManager(不依赖其他模块) +2. `_ready()` 中自动执行用例: + - 添加/删除弟子 → 信号是否正确发出 + - 查询(get_by_realm / count_mortals) + - `set_attr` → 信号带旧值/新值 + - `settle_month` → 境界提升/灵石消耗正确 + - `to_dict / load_from_dict` 往返一致 +3. `print` 输出 PASS/FAIL,编辑器直接运行场景验证