用途
本技能聚焦虚幻引擎中 C++ 与蓝图之间的边界层。该边界完全由 UHT 宏中声明的反射说明符定义:说明符写对了,就能得到干净、面向设计师的 API;写错了,则节点不出现、属性不显示或事件不触发。这是“C++ 基类 + 蓝图子类”模式中的契约层。
适用场景包括:为向设计师暴露 C++ 而选择 UFUNCTION/UPROPERTY/UCLASS 说明符;让蓝图通过事件覆盖或实现 C++ 行为;构建静态辅助函数的蓝图函数库;在 C++ 与蓝图之间传递类引用或软资产;定义可在 C++ 或蓝图中实现的共享接口契约。
主要能力
暴露函数(UFUNCTION)
BlueprintCallable:带副作用的函数,在蓝图中获得 exec 输入/输出引脚,应始终添加 Category。BlueprintPure:用于取值查询,无 exec 引脚,结果按每次求值缓存;避免在其中执行重负载工作,因为蓝图每次读取输出引脚都会重新求值。BlueprintImplementableEvent:由 C++ 触发、蓝图定义行为,UHT 生成 thunk,不可提供 C++ 函数体;在 C++ 中调用基名即可。BlueprintNativeEvent:提供_Implementation作为 C++ 默认实现,调用基名以便引擎在存在蓝图覆盖时路由过去;在 C++ 覆盖中调用Super::FuncName_Implementation(...)。
其他有用的函数说明符:CallInEditor(在细节面板添加按钮,仅编辑器)、BlueprintAuthorityOnly(蓝图只能在服务器/单人调用)、BlueprintCosmetic(专用服务器上跳过)、meta=(DisplayName="...")(覆盖节点标签)、meta=(ExpandEnumAsExecs="Param")(为每个枚举值创建一个 exec 引脚)。
暴露属性(UPROPERTY)
编辑/可见性说明符:EditAnywhere(原型与实例均可编辑)、EditDefaultsOnly(仅原型/类默认值)、EditInstanceOnly(仅放置/生成的实例)、VisibleAnywhere(到处只读显示)、VisibleDefaultsOnly(仅原型只读显示)。
蓝图访问说明符:BlueprintReadWrite(get+set 节点)、BlueprintReadOnly(仅 get)。它们与 Edit/Visible 轴相互独立,可按需组合。
常用 meta 标签:ClampMin/ClampMax(编辑器输入范围)、UIMin/UIMax(滑块范围)、ExposeOnSpawn="true"(生成引脚)、AllowPrivateAccess="true"(向蓝图暴露私有成员)、EditCondition="bSomeFlag"(标志为假时置灰)。
UCLASS 说明符
Blueprintable:设计师可创建该 C++ 类的蓝图子类。BlueprintType:该类可作为蓝图图中的变量类型。- 两者除非被覆盖,否则由子类继承。
MinimalAPI:仅导出 Cast<> 和虚表所需的类型信息,为不需要跨模块访问全部方法的类保持较低编译时间。
传递类引用与软资产
TSubclassOf<AProjectile>:类型安全的类引用,编辑器只显示 AProjectile 及其子类。TSoftObjectPtr<UTexture2D>:可异步加载的纹理,加载前不驻留内存。TSoftClassPtr<AAIController>:可异步加载的类,适用于流式场景。- 使用类引用生成:
GetWorld()->SpawnActor<AProjectile>(ProjectileClass, Location, Rotation)。软引用可通过 Asset Manager 或 RequestAsyncLoad 异步加载。
蓝图函数库
用于不绑定特定对象实例的工具函数,继承 UBlueprintFunctionLibrary,方法必须为 static,会作为全局节点出现在任意蓝图图中。UGameplayStatics 是典型的大型示例。
蓝图可实现接口
接口让不相关的类共享 C++/蓝图契约而无需共同父类。使用 UINTERFACE(MinimalAPI, Blueprintable) 声明,I 前缀类中提供 BlueprintNativeEvent 方法。C++ 实现:继承 IInteractable 并提供 Interact_Implementation;蓝图实现:在 Class Settings 添加接口并实现事件节点。从 C++ 安全调用:if (Target->Implements<UInteractable>()) IInteractable::Execute_Interact(Target, this);。注意 Cast<> 仅在接口由 C++ 实现时有效,蓝图实现需用 Execute_<FuncName>。
暴露给蓝图的委托
使用 DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam 声明,配合 UPROPERTY(BlueprintAssignable) 让设计师在事件图中绑定。委托必须是 DYNAMIC_MULTICAST,UHT 仅将该族暴露给蓝图。
使用方式
在 C++ 头文件中通过 UHT 宏声明类、函数、属性与接口,并选择合适的反射说明符;UHT 读取每个宏并生成元数据(存储在 UClass/UFunction/FProperty 对象中)与 thunk 函数(让蓝图调用 C++ 及反向调用的粘合层)。说明符是写给 UHT 的指令,而非运行时代码。
适用场景
- 为设计师暴露 C++ 功能并构建面向设计师的 API。
- 让蓝图覆盖或实现 C++ 行为。
- 构建静态辅助函数的蓝图函数库。
- 在 C++ 与蓝图之间传递类引用或软资产。
- 定义可在 C++ 或蓝图中实现的共享接口契约。
限制与注意事项
常见陷阱:未设置 Category 会落入扁平的 Default 组;BlueprintImplementableEvent 带 C++ 函数体会编译错误;直接通过 _Implementation 调用 BlueprintNativeEvent 会绕过蓝图覆盖;接口调用缺少 Execute_ 会静默跳过蓝图实现;私有成员上的 BlueprintReadWrite 若无 meta=(AllowPrivateAccess="true") 无法编译;向蓝图返回 const& 不安全,应按值返回;BlueprintPure 用于慢函数会导致蓝图每次连接节点都重跑;对仅蓝图实现者使用 Cast<IMyInterface> 返回 null;I 前缀接口类中忘记 GENERATED_BODY() 会导致 UHT 拒绝生成调度器。
版本说明:TObjectPtr<T> 是 UE5+ 的现代 UPROPERTY 成员惯用法,旧代码使用原始 T* 仍可用,新代码建议优先使用 TObjectPtr;UE 5.0+ 中 const 函数上的 BlueprintPure=false 会强制显示 exec 引脚;说明符集在 UE 5.x 中保持稳定,源码引用行号可能随补丁版本漂移,但头文件路径与枚举名稳定。