unreal-cpplisted
Install: claude install-skill Wade-DevCode/awesome-coding-skills-cn
# Unreal C++/蓝图
## 何时用
- 新建或修改任何继承自 UObject/AActor/UActorComponent 的 C++ 类时。
- 给蓝图暴露 C++ 函数或属性,或从 C++ 调用蓝图事件时。
- Actor 的 Tick 频率、Timer、委托连接有疑问时。
- 划分哪些逻辑该放 C++、哪些留给蓝图时。
- 遇到偶发崩溃、GC 踢掉对象、野指针问题时。
## 核心规则
### 1. UObject 与 GC:UPROPERTY() 是安全绳
**规则:** 所有持有 UObject 派生类(Actor、Component、Asset 等)的成员变量,必须加 `UPROPERTY()`;弱引用用 `TWeakObjectPtr`;原生裸指针不做持有。
**为什么——真实会犯的错:**
在 `.h` 里写了 `AEnemy* CachedEnemy;` 没加 `UPROPERTY()`,开发期看起来没问题,进入关卡切换或 GC 整理周期后,引擎把 `CachedEnemy` 回收了,下一帧 `CachedEnemy->TakeDamage(...)` 直接崩溃。Crash log 里只有 `Access violation`,根本看不出是 GC 问题,排查半天。
**怎么做:**
- 成员变量持�� UObject 子类 → 加 `UPROPERTY()`(至少空括号),让 GC 追踪引用计数。
- 不希望阻止 GC 回收(如缓存目标但目标销毁时自动置 null)→ 用 `TWeakObjectPtr<AEnemy>`,使用前先 `IsValid()`。
- 函数局部变量、函数参数、返回值不需要 `UPROPERTY()`,GC 周期内不会出问题。
- 禁止用裸指针做持有,`new UObject()` 也不要手动调,用 `NewObject<T>()` 或 `SpawnActor<T>()`。
---
### 2. 反射宏:按需标注,不滥标
**规则:** `UCLASS`/`UFUNCTION`/`UPROPERTY` 只在真正需要反射、蓝图互操时标注;不把所有东西都往蓝图暴露。
**为什么——真实会犯的错:**
把所有函数都加 `BlueprintCallable`、所有变量都加 `EditAnywhere`,编译时间膨胀,蓝图节点列表被几百个无意义函数污染,策划误用了不该在蓝图调的内部函数,出现生命周期顺序问题。另一个常见错误:忘记在 `UFUNCTION()` 里标 `BlueprintImplementableEvent` 却在 C++ 里给了函数体,导致链接错误,新手往往不知道该怎么修。
**怎么做:**
- 只给蓝图**调用**的函数加 `BlueprintCallable`;只给蓝图**重写**的函数加 `BlueprintImplementableEvent` 或 `BlueprintNativeEvent`。
- `BlueprintImplementableEvent` 的 C++ 函数**不能有函数体**;`BlueprintNativeEvent` 的实现写在 `FuncName_Implementation` 里。
- 纯 C++ 内部函数不加任何蓝图标记,保持私有或 protected。
- 变量只在需要编辑器/蓝图访问时才加 `EditAnywhere`/`BlueprintReadWrite`;运行时内部状态加 `Transient` 或不标。
---
#