新增P1模块拆分与弟子管理模块设计文档
This commit is contained in:
+141
@@ -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 完整化 |
|
||||
| 灵田品质 | 收获时按种植者技艺定品质,无随机 | 可加随机 |
|
||||
| 炼丹失败 | 材料足够即成功,品质随技艺浮动 | 可加失败率 |
|
||||
+85
@@ -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,编辑器直接运行场景验证
|
||||
Reference in New Issue
Block a user