From 03c765ced89665e58441682b558b539438cee8e6 Mon Sep 17 00:00:00 2001 From: chen Date: Thu, 6 Aug 2026 22:49:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Disciple=20=E5=A2=9E=E5=8A=A0=E5=85=A5?= =?UTF-8?q?=E5=AE=97=E6=97=B6=E9=97=B4=E5=BF=AB=E7=85=A7=EF=BC=8CD4=20?= =?UTF-8?q?=E5=90=8D=E5=BD=95=20UI=20=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/design/弟子系统设计.md | 98 ++++++++++++++++++++++++++++++-- src/Character/Disciple.gd | 9 +++ src/Character/DiscipleManager.gd | 6 +- 3 files changed, 107 insertions(+), 6 deletions(-) diff --git a/doc/design/弟子系统设计.md b/doc/design/弟子系统设计.md index 0959f0c..9e29180 100644 --- a/doc/design/弟子系统设计.md +++ b/doc/design/弟子系统设计.md @@ -1,7 +1,7 @@ -# 弟子系统设计(D3:生成 + 入宗分流) +# 弟子系统设计(D3:生成 + 入宗分流 / D4:名录 UI) -> 对应开发计划表 D3(8/5)。本文档只描述设计,不包含代码。 -> 状态:设计稿,待审阅通过后实现 +> 对应开发计划表 D3(8/5)与 D4(8/6)。本文档只描述设计,不包含代码。 +> 状态:D3 已实现;D4 设计稿,待审阅通过后实现 --- @@ -17,6 +17,9 @@ | `aptitude` | 枚举 Aptitude | 资质(入宗分流结果) | | `roots` | 枚举数组 SpiritRoot | 灵根列表(普通弟子 1~3 根,互不重复) | | `is_heavenly` | bool | 天灵根标记(稀有灵根,见枚举二) | +| `join_year` | int | 入宗年份(0 = 未入宗/候选),accept 时快照 GameState | +| `join_month` | int | 入宗月份 | +| `join_day` | int | 入宗日 | | `realm_index` | int | 大境界索引(0=练气),D5 修炼系统推进 | | `sub_realm_index` | int | 小境界索引(练气层数-1),D5 修炼系统推进 | @@ -57,6 +60,12 @@ 境界的成长、突破门槛、寿元计算全部留给 D5 修炼循环,D3 只负责初始状态。 +### 入宗时间字段说明 + +- `join_year/month/day` 在**入宗瞬间**(accept_applicant)快照 GameState 当前日期 +- 候选池弟子不设(0),拒绝入宗不产生记录 +- 本期只存不消费;入门天数换算(D5 修炼结算)、按入宗排序(列表)、资历事件(W8)后续使用 + --- ## 二、生成规则(随机性) @@ -173,7 +182,7 @@ aptitude_weights=[60, 30, 8, 2] - 每个候选一行:姓名/年龄/资质(天灵根标记)/灵根/境界 + "入宗"勾选框 - 底部:全部接受 / 全部拒绝 / 确定 - 开局模式确定按钮在选满 3 名前禁用;确定后关闭弹窗并恢复时间 -- 名录的可视化列表属于 D4(弟子列表 UI),届时由 `disciples_changed` 信号驱动 +- 名录的可视化列表见**第七节(D4 弟子名录 UI)** --- @@ -188,7 +197,86 @@ aptitude_weights=[60, 30, 8, 2] --- -## 七、验收清单(D3 交付标准) +## 七、弟子名录 UI(D4) + +> 对应开发计划表 D4(8/6):① 列表条目场景 ② 姓名/资质/境界显示 ③ 点击详情。交付标准:列表可浏览弟子。 + +### 1. 入口 + +- TopBar 顶部栏"**管理**"按钮(Button_StaffManagement,当前无功能)→ 打开弟子名录面板 +- 打开面板**不暂停时间**(浏览操作,不打断挂机节奏;招募弹窗优先级更高,弹出时覆盖其上) + +### 2. 面板结构(两层弹窗,复用青绿仙侠配色) + +**第一层:名录列表面板(DisciplesPanel)** + +| 元素 | 说明 | +|------|------| +| 标题 | "弟子名录(N 人)",N = 当前名录人数 | +| 列表区 | ScrollContainer 动态条目,一个弟子一行,按入宗顺序 | +| 条目内容 | 姓名 / 资质(含天灵根标记)/ 灵根 / 境界 + "详情"按钮 | +| 空状态 | 名录为空时显示"暂无弟子"提示 | +| 底部 | "关闭"按钮(也可点遮罩关闭) | + +**第二层:弟子详情弹窗(DiscipleDetailPanel)** + +| 元素 | 说明 | +|------|------| +| 标题 | 弟子姓名 + 天灵根标记 | +| 信息区 | 静态展示:资质 / 年龄 / 灵根 / 境界 / 编号 / **入宗时间** | +| 预留区 | 修炼进度、属性面板等 D5+ 扩展位置(本期留白) | +| 底部 | "关闭"按钮 | + +### 3. 数据驱动 + +- 面板监听 `DiscipleManager.disciples_changed` → 重建列表 +- 打开面板时也主动刷新一次(保证与名录同步) +- 条目与弟子数据一一对应:动态生成时把 Disciple 引用绑定到条目上,点"详情"直接取用 + +### 4. 文件与场景结构 + +``` +src/UI/Panels/DisciplesPanel/ +├── DisciplesPanel.tscn # 名录列表弹窗 +├── disciples_panel.gd +├── DiscipleDetailPanel.tscn # 弟子详情弹窗 +└── disciple_detail_panel.gd +``` + +- 两个弹窗都挂在 MainGame 下(默认隐藏),详情弹窗作为列表面板的子层(显示时盖在列表之上) +- 条目在代码中动态生成(与 RecruitPanel 同套路),不单独做条目场景(D4 拆解的"列表条目场景"用动态行实现即可) +- TopBar"管理"按钮在 `top_bar_hud.gd` 接线,调 `DisciplesPanel.show_panel()` + +### 5. 交互细节 + +- 详情弹窗从列表面板打开;关闭详情回到列表;关闭列表回到游戏 +- 列表浏览期间名录变化(如定期招募入宗)→ 列表实时刷新 +- 资质文字可用颜色区分(天骄金色、上品亮青),其余默认——视觉提示,本期可选 + +--- + +## 八、验收清单(D4 交付标准) + +- [ ] 点顶部"管理"按钮弹出弟子名录面板,显示当前已入宗弟子 +- [ ] 列表每行显示:姓名 / 资质(天灵根有标记)/ 灵根 / 境界 +- [ ] 名录为空时显示"暂无弟子";招募入宗后列表实时刷新 +- [ ] 点条目"详情"弹出详情弹窗,显示姓名/资质/年龄/灵根/境界/编号 +- [ ] 关闭详情回到列表,关闭列表回到游戏,无报错 +- [ ] 面板打开期间时间照常推进(不暂停) + +--- + +## 九、与后续任务衔接(D4 补充) + +| 后续任务 | 衔接方式 | +|----------|----------| +| D5 修炼循环 | 详情弹窗预留区填充:修为进度、突破按钮、寿元 | +| D6 建筑/职能系统 | 列表条目可扩展"职位/职能"列 | +| D8 存档接入 | 名录数据来源不变,仅序列化方式接入 | + +--- + +## 十、验收清单(D3 交付标准) - [ ] 项目能正常启动,无脚本报错 - [ ] **开局**:进入游戏即暂停,弹出"弟子入宗(开局招募)",显示 5 名候选 diff --git a/src/Character/Disciple.gd b/src/Character/Disciple.gd index d2b9cdb..69f56c7 100644 --- a/src/Character/Disciple.gd +++ b/src/Character/Disciple.gd @@ -23,6 +23,9 @@ var age: int = 0 var aptitude: Aptitude = Aptitude.ORDINARY var roots: Array[SpiritRoot] = [] # 普通弟子 1~3 根;天灵根固定 1 根 var is_heavenly: bool = false # 天灵根标记(3% 概率) +var join_year: int = 0 # 入宗年份(0 = 未入宗/候选),accept 时快照 +var join_month: int = 0 # 入宗月份 +var join_day: int = 0 # 入宗日 var realm_index: int = 0 # 大境界索引(0=练气) var sub_realm_index: int = 0 # 小境界索引(练气层数-1) @@ -40,3 +43,9 @@ func get_realm_text() -> String: if realm_index == 0: return "%s%d层" % [REALM_NAMES[realm_index], sub_realm_index + 1] return "%s%s" % [REALM_NAMES[realm_index], ["初期", "中期", "后期", "圆满"][sub_realm_index]] + +## 入宗时间文本,如 "1年2月3日";未入宗返回空串。 +func get_join_date_text() -> String: + if join_year <= 0: + return "" + return "%d年%d月%d日" % [join_year, join_month, join_day] diff --git a/src/Character/DiscipleManager.gd b/src/Character/DiscipleManager.gd index e9f664b..5332a7d 100644 --- a/src/Character/DiscipleManager.gd +++ b/src/Character/DiscipleManager.gd @@ -22,6 +22,7 @@ const SURNAMES: Array[String] = [ "林", "苏", "叶", "萧", "顾", "沈", "楚", "白", "陆", "云", "柳", "秦", "江", "韩", "洛", "慕", "夜", "凤", "凌", "姜", "谢", "赵", "魏", "许", + "司", "夏", "方", "唐", "霍", "段", "卓", "陈", ] ## 名用字池(修仙风)。 @@ -65,7 +66,7 @@ func generate_applicants(count: int, is_opening := false) -> void: applicants.append(_create_applicant()) applicants_generated.emit(is_opening) -## 接受一名候选弟子:分配 ID 并移入名录(候选池 → 名录)。 +## 接受一名候选弟子:分配 ID、快照入宗时间并移入名录(候选池 → 名录)。 ## @param d: 要接受的候选 func accept_applicant(d: Disciple) -> void: if not applicants.has(d): @@ -73,6 +74,9 @@ func accept_applicant(d: Disciple) -> void: applicants.erase(d) d.id = _next_id _next_id += 1 + d.join_year = GameState.year + d.join_month = GameState.month + d.join_day = GameState.day disciples.append(d) disciples_changed.emit() print("弟子入宗:%s %d岁 | %s资质%s | %s灵根 | %s" % [