「百考通」的降重与降AI对文本进行智能重组
2026/7/8 8:47:30
在标准 C++ 中,调用函数是“硬跳转”:编译器在编译期确定内存地址。但在虚幻引擎中,函数需要具备**“动态分发”**的能力。UFUNCTION宏通过“劫持”函数名,在静态的 C++ 之上构建了一套动态调用体系。
| 特性 | 标准 C++ 函数 | 虚幻 C++ (UFUNCTION) |
|---|---|---|
| 可见性 | 仅限代码链接期 | 全局运行时可见,蓝图/编辑器可识别 |
| 调用方式 | 内存地址直接跳转 | 支持字符串搜索调用、网络转发调用 |
| 多态性 | 依赖原生虚函数表 (vtable) | 支持蓝图重写、C++/脚本混合多态 |
| 参数传递 | 栈/寄存器传参 | 支持通过反射数据包(Stack Buffer)传参 |
通过在UFUNCTION()中添加不同的说明符,你可以精准定义函数在引擎中的身份。
BlueprintCallable:最常用的标记,让函数在蓝图中作为一个节点被手动调用。BlueprintPure:定义“纯函数”。这种函数没有执行线(白线),通常用于获取数据而不改变对象状态。BlueprintImplementableEvent:C++ 声明触发,蓝图完全实现。BlueprintNativeEvent:C++ 提供默认实现(_Implementation),蓝图可以重写。Server:客户端调用,服务器执行。Client:服务器调用,特定客户端执行。NetMulticast:服务器调用,所有连接的客户端同步执行。Reliable/Unreliable**:定义网络包是否必须到达(可靠性)。WithValidation:要求必须实现_Validate逻辑,用于服务器防外挂检查。Exec:将函数变为控制台命令,在游戏中按~键输入函数名即可运行。CallInEditor:在编辑器的属性面板中生成一个按钮,点击即可在非运行状态下触发该函数。Category:定义函数在蓝图搜索列表中的目录分类。meta)meta = (AllowPrivateAccess = "true"):允许私有函数在蓝图中被访问。meta = (WorldContext = "WorldContextObject"):标记某个参数为世界上下文,蓝图调用时会自动填充,无需手动连线。当你编译一个带有UFUNCTION的类时,UHT 会在.generated.cpp中为你生成一个以exec开头的静态函数。这就是Thunk 函数。
蓝图虚拟机(VM)手里只有一个uint8*类型的栈空间(Stack Buffer)。Thunk 的工作就是“翻译”:它从虚拟机栈中取出字节,转换成真实的 C++ 类型,然后再调用你写的函数。
voidAMyActor::execNativeEvent(FFrame&Stack,RESULT_DECL){P_GET_PROPERTY(FFloatProperty,Value);// 从栈里解析出参数P_FINISH;P_NATIVE_BEGIN;this->NativeEvent_Implementation(Value);// 真正调用你的 C++P_NATIVE_END;}UCLASS()classAMyActor:publicAActor{GENERATED_BODY()public:UFUNCTION(BlueprintCallable)voidSimpleCall();UFUNCTION(BlueprintNativeEvent)voidNativeEvent(floatValue);UFUNCTION(BlueprintImplementableEvent)voidOnlyBlueprintEvent();UFUNCTION(Server,Reliable,WithValidation)voidServer_UpdateHealth(floatNewHealth);};voidAMyActor::SimpleCall(){UE_LOG(LogTemp,Warning,TEXT("Simple Call"));}voidAMyActor::NativeEvent_Implementation(floatValue){UE_LOG(LogTemp,Warning,TEXT("Default C++ Logic"));}// OnlyBlueprintEvent 无需且禁止在 .cpp 实现boolAMyActor::Server_UpdateHealth_Validate(floatNewHealth){returnNewHealth>=0.0f;// 防外挂校验}voidAMyActor::Server_UpdateHealth_Implementation(floatNewHealth){CurrentHealth=NewHealth;}| UFUNCTION 类型 | 实现后缀 | 是否有 Thunk (exec) | 核心逻辑流 |
|---|---|---|---|
| BlueprintCallable | 无 | 有 | VM -> Thunk -> C++ 原生函数 |
| BlueprintNativeEvent | _Implementation | 有 | 原名函数 -> (判断) -> 蓝图或 C++ Impl |
| BlueprintImplementableEvent | 无实现 | 有 | 原名函数 -> 直接丢给 VM 执行蓝图 |
| Server / Client | _Implementation | 有 | 原名函数 -> 网络序列化 -> 远端 Thunk -> Impl |
UFUNCTION是通过Thunk 函数抹平了强类型 C++ 与动态虚拟机之间的鸿沟。你写下的每一行_Implementation,都在这套名为“反射”的宏大剧本中扮演着保底逻辑的角色。
下一篇我们将探讨:《06. UE 的枚举与接口:UENUM 和 UINTERFACE》。