蓝图与 C++ 互调
自动关联目录:蓝图与 C++ 互调
官方依据:Blueprints Visual Scripting 已明确——C++ 实现中的 Blueprint 专用标记让程序员能创建可被设计者扩展的基线系统。本篇就是这套标记的用法与代价。
1. 定位
互调的纽带是反射(见 反射与 UHT):C++ 用宏把类型信息暴露出去,蓝图才能看见并调用。
一句话定位:两个方向的调用机制完全不同——C++ 调用蓝图靠"事件钩子",蓝图调用 C++ 靠"反射可见"。
2. 标记速查
让蓝图能看见 C++
| 标记 | 作用 |
|---|---|
UCLASS(Blueprintable) | 可被蓝图继承 |
UPROPERTY(BlueprintReadWrite) | 蓝图可读写 |
UPROPERTY(BlueprintReadOnly) | 蓝图只读 |
UFUNCTION(BlueprintCallable) | 蓝图可调用 |
UFUNCTION(BlueprintPure) | 无副作用的纯函数 |
UFUNCTION(BlueprintImplementableEvent) | C++ 声明、蓝图实现 |
UFUNCTION(BlueprintNativeEvent) | C++ 有默认实现、蓝图可覆写 |
USTRUCT(BlueprintType) | 结构体可用于蓝图 |
UENUM(BlueprintType) | 枚举可用于蓝图 |
忘标 UPROPERTY 的字段对蓝图不存在——这是"蓝图里看不到这个变量"的唯一原因(见 反射与 UHT)。
让 C++ 能触发蓝图
// 声明:蓝图里实现
UFUNCTION(BlueprintImplementableEvent)
void OnDamaged(float Amount);
// C++ 里触发(蓝图的实现会被调用)
OnDamaged(50.f);
// 带默认实现版本
UFUNCTION(BlueprintNativeEvent)
void OnDeath();
void AMyActor::OnDeath_Implementation() { /* C++ 默认实现 */ }BlueprintNativeEvent 的实现必须写在 _Implementation 后缀的函数里,直接写原函数名会链接失败。
3. 反向:蓝图调 C++
UFUNCTION(BlueprintCallable, Category = "Combat")
void ApplyDamage(AActor* Target, float Amount);蓝图中直接作为节点出现。代价:走一次反射调用(比直接 C++ 调用慢,见下)。
4. 代价与权衡
| 设计 | 收益 | 代价 | 什么时候不该用 |
|---|---|---|---|
| BlueprintCallable | 蓝图能用 | 反射调用开销 | 每帧高频调用不应走蓝图 |
| BlueprintImplementableEvent | 解耦,C++ 不关心实现 | C++ 侧无法保证有实现 | 必须有默认行为时用 NativeEvent |
| BlueprintNativeEvent | 有默认实现 | 调用多一层间接 | 纯 C++ 逻辑不必用它 |
| BlueprintReadWrite | 蓝图可调参 | 外部可随意改,破坏封装 | 内部状态应只读或私有 |
| BlueprintPure | 无副作用,蓝图里清爽 | 被多次调用时可能重复计算 | 昂贵计算不要标 Pure |
5. 踩坑与排查
| 坑 | 现象 | 怎么验证 |
|---|---|---|
| 蓝图看不到变量/函数 | 不存在 | 检查是否标了 UPROPERTY / UFUNCTION |
BlueprintNativeEvent 链接失败 | 编译错误 | 实现是否写成 _Implementation |
| 热路径走 BlueprintCallable | 慢 | 改为 C++ 内部调用 |
| BlueprintPure 里做重计算 | 被重复调用 | 去掉 Pure,或缓存 |
| 蓝图改了不该改的字段 | 状态混乱 | 改 BlueprintReadOnly,或加校验 |
忘记 Blueprintable | 无法继承 | 检查 UCLASS 标记 |
| 结构体/枚举在蓝图不可用 | 选不到类型 | 加 BlueprintType |
6. 排查顺序
1. 蓝图看不到?→ 反射标记
2. C++ 调不动蓝图?→ 是否用 ImplementableEvent/NativeEvent 触发
3. NativeEvent 报错?→ _Implementation 后缀
4. 慢?→ 热路径是否走了反射调用
5. 状态被乱改?→ 收紧读写权限参考
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/e2cd3df0.html
更新于:2026年10月10日