b2820ec024
- 新增 problem-solving skill:固化「问题分析→工作记录→知识沉淀」9步流程与3模板 - 新建 docs/knowledge/ 经验知识库(README/INDEX/临时方案登记/坑-UE5引擎含2条迁移示例) - GIT-GUIDE 补 §2.7 临时代码 [TEMP-INVESTIGATE] 约定、§2.8 fix 提交引用 issue - CLAUDE.md 项目管理段加问题管理引用 - 配套 Gitea 标签 type:bug / type:investigation(后台已建)
29 lines
2.3 KiB
Markdown
29 lines
2.3 KiB
Markdown
# 坑-UE5引擎
|
||
|
||
> UE5 引擎相关的坑:Actor/Component 生命周期、初始化时序、引擎 API 陷阱等。
|
||
> 条目按 ID 排列。新增条目时同步更新 [INDEX.md](INDEX.md)。
|
||
|
||
---
|
||
|
||
### [K-001] Actor BeginPlay 时序竞争:子系统 Driver 可能晚于 Character 初始化
|
||
|
||
- **来源**: P-013 实现偏差报告 · 偏差3
|
||
- **症状**: 在 `AChildHoodCharacter::BeginPlay` 中通过 `ASystemDriver::Get` 取 Driver,再读子系统(如收集系统)的进度数据时,可能读到未初始化的值(Progress=0、CollectedIDs 空),导致进度 Widget 显示错误或存档恢复失败。
|
||
- **根因**: UE5 **不保证不同 Actor 的 BeginPlay 执行顺序**。Character 可能先于 `ASystemDriver` 完成 BeginPlay——此时 Driver 虽然存在,但其持有的子系统尚未执行 `RestoreFromPersistence`。
|
||
- **避坑做法**: 不要在 `BeginPlay` / `Initialize` 里立即创建依赖其他子系统的对象、或读取其状态。改为**首次有效 Tick 时懒创建**——等到 World 完全就绪、依赖子系统完成初始化后再创建/读取。
|
||
- **状态**: ✅正式方案(已用于 `UCollectionHUDComponent` 的进度 Widget 创建)
|
||
- **关联**: `docs/technical/收集系统-技术方案.md` §6、`Source/.../CollectionHUDComponent.cpp`
|
||
|
||
---
|
||
|
||
### [K-002] Component 持有的 Timer / Widget 必须在 EndPlay 清理,防 Respawn 野指针
|
||
|
||
- **来源**: P-013 实现偏差报告 · 审查修复2
|
||
- **症状**: 角色 Respawn(销毁旧 Character、重建新 Character)时崩溃——旧 Component 上还挂着 `SetTimer` 注册的回调,触发时访问已销毁的 UMG Widget,野指针。
|
||
- **根因**: Component 被销毁时,UE 不会自动清理你手动注册的 `FTimerHandle`,也不会自动移除 `AddToViewport` 的 Widget。这些引用悬挂,下次 Tick 或 Timer 触发即崩。
|
||
- **避坑做法**: 凡是 Component 持有 `FTimerHandle`(`SetTimer` 注册过)或 `AddToViewport` 的 UMG Widget,**必须 override `EndPlay`**,在里头:
|
||
- `GetWorld()->GetTimerManager().ClearTimer(MyTimerHandle);`(清所有相关句柄)
|
||
- `if (MyWidget) MyWidget->RemoveFromParent();`(Widget 还有效则移除)
|
||
- **状态**: ✅正式方案(项目所有 Character 持有 Component 的卫生写法,保持一致)
|
||
- **关联**: `Source/.../CollectionHUDComponent.cpp` EndPlay
|