- _init 形参由 Dictionary[String, Variant] 放宽为 Dictionary: duplicate() 产物为普通字典,运行时类型校验导致 create() 失败 - SUB_MAX_BY_REALM 索引两处改用显式 int 声明,消除 Cannot infer 错误 - doc/弟子管理.md 补充修炼经验说明
125 lines
5.6 KiB
Markdown
125 lines
5.6 KiB
Markdown
# 弟子管理模块设计
|
||
|
||
模块位置: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,编辑器直接运行场景验证
|
||
|
||
# 弟子属性
|
||
|
||
## 属性列表
|
||
|名称|范围|说明|
|
||
|:---|:---|:---|
|
||
|metal|[0, 100]|金属性值|
|
||
|wood|[0, 100]|木属性值|
|
||
|water|[0, 100]|水属性值|
|
||
|fire|[0, 100]|火属性值|
|
||
|earth|[0, 100]|土属性值|
|
||
|efficiency|[1, 100]|灵气吸收效率,决定修炼速度,隐藏属性|
|
||
|realm_level|[0, 5]|大境界,凡人、练气、筑基、金丹、元婴、化神|
|
||
|sub_realm_level|[1, 13]|凡人只有一个小境界;练气13个小境界,其他各有前、中、后、大圆满四个小境界|
|
||
|cultivation_exp|[0, 2147483647]|修炼经验|
|
||
|farming_skill_exp|[0, 2147483647]|耕作技能经验|
|
||
|farming_skill_level|[0, 10]|炼丹技能等级|
|
||
|herb_farming_skill_exp|[0, 2147483647]|药草耕作技能经验|
|
||
|herb_farming_skill_level|[0, 10]|炼丹技能等级|
|
||
|alchemy_skill_exp|[0, 2147483647]|炼丹技能经验|
|
||
|alchemy_skill_level|[0, 10]|炼丹技能等级|
|
||
|loyalty|[0, 100]|忠诚度|
|
||
|
||
- **修炼经验说明**:每个小境界都有一个经验上限,跨越小境界,溢出部分会继承到下一个小境界。跨越大境界,溢出部分清零。
|
||
|
||
- **技能经验说明**:耕作技能经验、药草耕作技能经验、炼丹技能经验,每跨越一个等级,溢出的经验会继承到下一个等级,直到升满为止,不会有任何经验提升。每个等级所需的经验为需要在文件中配置。
|
||
|
||
|
||
## 初始分配方式
|
||
```mermaid
|
||
graph TD
|
||
A[分配属性总量,按正正态分布] --> B[随机分配5种属性,属性之和为1] --> C[分配灵气利用率]
|
||
```
|
||
|
||
## 修炼说明
|
||
|
||
每个小境界修炼需要的经验 = 基础经验值 * 属性总量
|
||
|
||
经验获取量 = 基础经验 * 灵气吸收效率
|