docs(collection): P-013偏差报告与Widget蓝图指南
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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 范围
|
||||
@@ -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/名称映射。
|
||||
Reference in New Issue
Block a user