From 870976fa7b5c3d6c3c59d3f5b5b14a53746c8083 Mon Sep 17 00:00:00 2001 From: starmen1265 Date: Mon, 15 Jun 2026 05:13:28 +0800 Subject: [PATCH] =?UTF-8?q?docs(collection):=20P-013=E5=81=8F=E5=B7=AE?= =?UTF-8?q?=E6=8A=A5=E5=91=8A=E4=B8=8EWidget=E8=93=9D=E5=9B=BE=E6=8C=87?= =?UTF-8?q?=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- docs/plans/reports/P-013-实现偏差报告.md | 105 ++++++++++++++++++ .../笔记/P-013-收集系统Widget蓝图创建指南.md | 90 +++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 docs/plans/reports/P-013-实现偏差报告.md create mode 100644 docs/technical/笔记/P-013-收集系统Widget蓝图创建指南.md diff --git a/docs/plans/reports/P-013-实现偏差报告.md b/docs/plans/reports/P-013-实现偏差报告.md new file mode 100644 index 0000000..1b9bc9c --- /dev/null +++ b/docs/plans/reports/P-013-实现偏差报告.md @@ -0,0 +1,105 @@ +# 收集系统(P-013)实现偏差报告 + +- **任务ID**: P-013 +- **对应执行案**: `docs/design/收集系统-执行案.md` (v0.1.1) +- **对应技术方案**: `docs/technical/收集系统-技术方案.md` (v1.0 架构解耦) +- **实现日期**: 2026-06-15 +- **实现者**: 程序 Agent +- **审查**: 多维度对抗性静态审查(10 agent),结论 0 critical / 0 major / 2 minor(已修复) + +--- + +## 一、行为规则覆盖核对(对照执行案逐条) + +执行案全部行为规则均已实现覆盖,**无行为规则层面的重大偏差**。 + +| 执行案条目 | 实现位置 | 状态 | +|------------|---------|------| +| **一、5步流程** | | | +| 步骤1 查品类 | `FCollectionManager::OnItemObtained` 比对 `Config.TrackedCategory` | ✅ | +| 步骤2 查重复 | `ProcessNewCollection` 的 `CollectedIDs.Contains` | ✅ | +| 步骤3 记录 | `CollectedIDs.Add` + `Progress = Num()` + `SaveStateToPersistence` | ✅ | +| 步骤4 弹通知 | `RefreshCachedInfo` 生成文本 → HUDComponent Tick 检测 → 延迟创建 | ✅ | +| 步骤5 完成判定 | `Progress >= TotalCount` → `bIsComplete`/`bJustCompleted` | ✅ | +| **二、收集通知UI** | | | +| 新收集触发 | HUDComponent Tick 检测 Progress 变化 | ✅ | +| 延迟 0.3s | `NotifDelayTimerHandle` + `Config.NotifDelay` | ✅ | +| 内容「发现了新的杂物,进度X/Y」 | `RefreshCachedInfo` 的 `FString::Printf` | ✅ | +| 浅金色 #F0D060 | `Config.NotifTextColor` → Widget `SetColorAndOpacity` | ✅ | +| 淡入0.2/停留2.0/淡出0.3 | Widget `InitializeNotif` 三段时序 | ✅ | +| 最大同屏2条 | `ActiveNotifications.Num() >= MaxSimultaneousNotifs` | ✅ | +| **三、进度UI** | | | +| 左上角3%边距 | 蓝图布局(指南已说明) | ✅ | +| 格式「📦杂物X/Y」 | `UCollectionProgressWidget::UpdateProgress` | ✅ | +| 常驻显示 | `CreateProgressWidget` + `AddToViewport(5)` | ✅ | +| 弹性1.2x/0.2s | `BounceAnim` 动画 | ✅ | +| **四、完成表现** | | | +| 进度金色1.4x/0.5s | `SetCompleteStyle` + `CompleteAnim` | ✅ | +| 通知消失+0.5s后中心提示 | `TriggerCompletionSequence` 的 `TotalDelay` | ✅ | +| 「杂物全部收集完成!」2.0s | `ShowComplete` | ✅ | +| **五、边界情况** | | | +| 重复物品 | `CollectedIDs` 查重拦截 | ✅ | +| 完成后继续通知 | 查重 + `bCompletionShown` 一次性 | ✅ | +| 重启恢复 | `RestoreFromPersistence`(Driver.BeginPlay 调用) | ✅ | + +--- + +## 二、实现偏差清单 + +### 偏差 1:`FInteractableData` 新增 `Category` 字段(跨交互系统数据结构) +- **对应执行案条目**: 第一节步骤1「查品类」 +- **偏差等级**: 轻微 +- **原方案**: 技术方案第13节回调签名 `(ItemId, DisplayName, Category)` 隐含要求 Category 数据,但 `FInteractableData`(交互系统)原无此字段 +- **实际实现**: 在 `Interaction/InteractionTypes.h` 的 `FInteractableData` 新增 `UPROPERTY Category`(FName,拾取/翻找物填"杂物",非收集物留空) +- **偏差原因**: 收集系统查品类必须有 Category 数据源,原数据结构缺失,需补字段。此为实现技术方案的必要数据结构扩展,不改任何行为规则 +- **建议处理**: 文档同步——在交互系统技术方案补记 `FInteractableData.Category` 字段;交互物配置时需填写(P-016 配置拾取物时执行) + +### 偏差 2:`FCollectionCachedInfo::Reset()` 改名为 `ResetTransient()` +- **对应执行案条目**: 无(技术方案数据结构细节) +- **偏差等级**: 轻微 +- **原方案**: 技术方案第5节定义 `void Reset()` +- **实际实现**: 改名为 `ResetTransient()` +- **偏差原因**: 原 `Reset()` 名易误解为重置全部字段,实际只重置瞬时态(`bJustCompleted`/`PendingNotificationText`/`LastCollectedItemId`),保留 `Progress`/`TotalCount`/`bIsComplete`。新名准确表达语义,防误用 +- **建议处理**: 文档同步——技术方案第5节同步改名 + +### 偏差 3:进度 Widget 懒创建(非 Initialize 即创建) +- **对应执行案条目**: 第三节「游戏开始后始终可见」 +- **偏差等级**: 轻微(行为不变,仅创建时机延迟一帧) +- **原方案**: 技术方案第6节 `CreateProgressWidget` 在 `Initialize`/`BeginPlay` 时创建 +- **实际实现**: `UCollectionHUDComponent` 改为首次有效 Tick 时懒创建 `ProgressWidget` +- **偏差原因**: 规避 `AChildHoodCharacter::BeginPlay` 与 `ASystemDriver::BeginPlay` 的时序竞争——Character 可能先于 Driver 初始化,此时 `ASystemDriver::Get` 返回的 Driver 可能尚未完成 `CollectionManager.RestoreFromPersistence`。懒创建确保 World 就绪 + Driver 完成初始化后再创建,进度值正确 +- **建议处理**: 保留(更稳健);文档同步——技术方案第6节补记懒创建策略 + +### 偏差 4:Widget 三段时序用 `SetTimer` 而非动画完成委托 +- **对应执行案条目**: 第二节通知「淡入→停留→淡出」 +- **偏差等级**: 轻微(行为等价) +- **原方案**: 技术方案提及 UMG Animation 三段生命周期 +- **实际实现**: 淡出阶段用 `SetTimer(FadeOutDuration)` 计时后 `RemoveFromParent`,而非监听 `UUserWidget::OnAnimationFinished` 委托 +- **偏差原因**: 避免动画完成委托绑定的复杂度;计时器时长与动画时长一致,行为完全等价 +- **建议处理**: 保留(实现更简洁) + +### 偏差 5:3 个 WBP Widget 蓝图资产未创建(交付边界划分) +- **对应执行案条目**: 技术方案第7节美术资源(3个 UMG Widget) +- **偏差等级**: 轻微(逻辑层完整,UI 资产归 P-016) +- **原方案**: 技术方案交付物含 3 个 WBP 蓝图 +- **实际实现**: 3 个 Widget 的 **C++ 基类已全部实现**(`UCollectionNotifWidget`/`UCollectionProgressWidget`/`UCollectionCompleteWidget`,含 `BindWidget` 绑定契约);WBP 蓝图(.uasset 视觉布局)未创建 +- **偏差原因**: 与用户对齐的交付边界——C++ 基类属 P-013(程序),WBP 蓝图创建属 P-016(Widget 表现层接通,用户已决定新开任务)。无 WBP 时 C++ 判空跳过 UI 创建,收集逻辑仍正常运行 +- **建议处理**: 已产出创建指南 `docs/technical/笔记/P-013-收集系统Widget蓝图创建指南.md`;WBP 创建纳入 P-016 执行 + +--- + +## 三、审查修复(非偏差,对抗性审查后的质量提升) + +多维度审查 workflow(5 维度:编译/架构/规则/集成/生命周期)发现并已修复 2 项 minor: + +1. **日志一致性**:`CollectionHUDComponent.cpp` 的 `UE_LOG(LogTemp, ...)` 改为项目类别 `UE_LOG(LogChildHood, ...)`,与逻辑/驱动/持久层一致 +2. **EndPlay 生命周期清理**:`UCollectionHUDComponent` 补 `EndPlay` override,清理 `NotifDelayTimerHandle`/`CompleteTimerHandle` + 移除挂载 Widget,消除角色 Respawn 时悬挂 timer 的野指针风险(与项目其他 Character 的卫生写法一致) + +--- + +## 四、总结 + +- **行为规则覆盖**:执行案全部规则已实现,无重大行为偏差 +- **实现偏差**:5 项,全部轻微(4 项为技术方案层面的实现决策/命名/时序优化,1 项为交付边界划分) +- **建议**:偏差 1/2/3 在下次技术方案文档同步时更新;偏差 5 纳入 P-016 执行;偏差 4 保留 +- **遗留**:3 个 WBP 蓝图 + 拾取物交互物配置(Category/ItemId/Effect)属 P-016 范围 diff --git a/docs/technical/笔记/P-013-收集系统Widget蓝图创建指南.md b/docs/technical/笔记/P-013-收集系统Widget蓝图创建指南.md new file mode 100644 index 0000000..5223272 --- /dev/null +++ b/docs/technical/笔记/P-013-收集系统Widget蓝图创建指南.md @@ -0,0 +1,90 @@ +# 收集系统 Widget 蓝图创建指南(P-013) + +> 配套 C++ 代码:`Source/ChildHood/Collection/` 下的 3 个 Widget 基类 +> 对应技术方案:`docs/technical/收集系统-技术方案.md` 第7节(美术资源) +> 状态:C++ 基类已就位,需在 UE 编辑器创建 3 个 UMG 蓝图并配置角色 + +--- + +## 创建步骤 + +3 个 Widget 蓝图都需**继承对应 C++ 基类**,并确保组件名/动画名与 `BindWidget`/`BindWidgetAnim` 精确匹配(否则运行时绑定失败、C++ 判空跳过对应逻辑)。 + +### 1. WBP_CollectionNotification(收集通知) + +| 项 | 值 | +|----|----| +| 父类 | `UCollectionNotifWidget` | +| 路径 | `Content/UI/WBP_CollectionNotification` | +| ZOrder | 10(C++ `AddToViewport(10)`) | + +**必需绑定组件**(名字必须完全一致): +- `TextBlock` 名 **`NotifTextBlock`** — 通知文字 +- `WidgetAnimation` 名 **`FadeInAnim`** — 淡入(整体 Opacity 0→1,0.2s) +- `WidgetAnimation` 名 **`FadeOutAnim`** — 淡出(整体 Opacity 1→0,0.3s) + +**布局**:右上角锚点(与拾取通知错位,执行案第二节「在拾取通知下方」)。 +**文字颜色**:由 C++ 通过 `NotifTextColor`(浅金色 #F0D060)运行时设置,蓝图 TextBlock 默认颜色无所谓。 + +--- + +### 2. WBP_CollectionProgress(进度 HUD) + +| 项 | 值 | +|----|----| +| 父类 | `UCollectionProgressWidget` | +| 路径 | `Content/UI/WBP_CollectionProgress` | +| ZOrder | 5 | + +**必需绑定组件**: +- `TextBlock` 名 **`ProgressTextBlock`** — 进度文本(C++ 设为 `📦 杂物 X/Y`) +- `WidgetAnimation` 名 **`BounceAnim`** — 数字弹性(`ProgressTextBlock` 的 RenderScale 1.0→1.2→1.0,0.2s) +- `WidgetAnimation` 名 **`CompleteAnim`** — 完成弹性(RenderScale→1.4x,0.5s) + +**布局**:左上角锚点(Anchors Top Left),距左 3% 屏宽、距上 3% 屏高(执行案第三节)。 +**颜色**:C++ `NormalColor`(白)/`CompleteColor`(金 #F0D060)运行时切换,蓝图默认白色即可。 + +--- + +### 3. WBP_CollectionComplete(完成提示) + +| 项 | 值 | +|----|----| +| 父类 | `UCollectionCompleteWidget` | +| 路径 | `Content/UI/WBP_CollectionComplete` | +| ZOrder | 20 | + +**必需绑定组件**: +- `TextBlock` 名 **`CompleteTextBlock`** — 完成文字(C++ 设为「杂物全部收集完成!」) +- `WidgetAnimation` 名 **`FadeInAnim`** — 淡入 +- `WidgetAnimation` 名 **`FadeOutAnim`** — 淡出 + +**布局**:中心锚点(Anchors Center),白色大字,屏幕正中。 +**显示时序**:C++ 控制(淡入→停留 2.0s→淡出→自移除),蓝图只做视觉。 + +--- + +## 配置角色蓝图 + +在角色蓝图(`BP_ChildHoodCharacter` 或当前使用的角色蓝图)中,选中 `CollectionHUDComponent`,在 Details 面板设置三个 WidgetClass: + +``` +NotifWidgetClass = WBP_CollectionNotification +ProgressWidgetClass = WBP_CollectionProgress +CompleteWidgetClass = WBP_CollectionComplete +``` + +> 未设置时 C++ 判空跳过 UI 创建,收集逻辑仍正常运行(仅无 UI 显示)。补全蓝图后即完整可玩。 + +--- + +## 配置拾取物交互物(与交互系统 P-016 配合) + +收集系统通过 `AddToBackpack` Action 接收物品事件。每个拾取/翻找物的 `InteractableComponent.Data` 需配置: + +- `Category` = **`杂物`**(关键!收集系统据此判定追踪品类) +- `ItemId` = 唯一 ID(如 `marble_blue`、`card_wusong`) +- `DisplayName` = 显示名(如 `彩色弹珠(蓝色)`) +- `InteractEffect` 含 `AddToBackpack` Action(拾取物在动画物品消失时间点触发) + +详见执行案「v0.1 杂物品类清单」10 个物品的 ItemId/名称映射。