根据class获取值_UE4获取UProperty的值,以及一些情况下的UClass获取

4ecaf98ab5ed653efe3b0f1b5eb4fe8f.png

最近因为一些需求,想要访问一下UE4放在Protected或者Private里的属性,或者需要在C++里获取蓝图里创建的变量。于是研究了一下通过UProperty获取和设置成员变量。

首先,获取一个Class里的所有Uproperty,以及读出其值的方式UE4源码里有很多,随便找了一段贴在下面。

e9234e1945a40b4a0fb5e8d4e14f4c70.png

通过TFieldIterator 获取某一个Class里所有的UProperty的迭代器,这里的UProperty就是类的某个成员变量的反射信息,然后经过循环遍历所有的UProperty的迭代器,根据其存储的变量反射信息找到指定的变量。上图里是筛选出结构体变量,常用比较多的可以通过名字 It->GetName(FString &)做筛选。然后使用 UProperty的ContainerPtrToValuePtr(UObject* ContainerPtr,..)来获取指定对象的成员变量。

要是用这种方式获取并修改变量得要知道2个信息。

1.UClass

2.UClass创建出来的类对象

以此引申出UE4里各种情况下获取UClass的方式(欢迎大佬补充)

1.已获得类实例对象,并且获取的成员变量就是当前指针类型:

如 UObject* Ptr = NewObject<UObject>();你要获取的变量就是UObject上的,且你的对象是UObject的子类。那么直接UObject::StaticClass()获取UClass,或者Ptr ->StaticClass()获取Uclass,集齐两个要数,开始循环吧。

2.已获得类实例对象,但是获取的成员变量不是当前指针类型:

如 UObject* Ptr = GetWorld()->SpawnActor<AActor>();你要获取的变量是Actor上的,但是你的对象是被UObject* 引用的。那么请用Ptr ->GetClass()获取Uclass。或许有人说这个直接用AActor:::StaticClass()不就好了么。但是有时候这个变量是在蓝图创建的,要获取蓝图实例对象上蓝图里创建的某个变量,那么就只有这样获取了。

3.已获取的是UBlueprint的对象,要获取并修改这个蓝图资源上的某个变量。

这种情况常发生在需要修改蓝图资源的情况。这时我们是既不知道UClass,也不知道UClass创建出来的类对象。

要获取UClass:

UBlueprint的基类有一个GeneratedClass变量就是其UClass

要获取对象:

UE4编辑器在初始化时会给每一个UClass创建一个DefaultObject,通过UClass的对象获取,其实DefaultObject也就是蓝图资源所对应的对象,修改了其变量值,就是修改了蓝图资源上对应变量的值。当然要真正的修改资源上的数据,需要在修改后保存资源。后面会贴上保存资源的方式。

如此一来就集齐了两个要数,可以开始循环。

PS:在第三种情况下不能用ContainerPtrToValuePtr获取指定对象的成员变量,需要用

ContainerPtrToValuePtrForDefaults函数获取。

此处为简易粗暴的保存蓝图资源方式

9148192bcb95b3ecf2744bab2430c2a1.png
<think>嗯,用户之前问过如何在UE5的蓝图函数库中获取一个静态void函数的输出,现在他进一步提问,想获取的不是蓝图函数的普通函数的输出。我需要先理解他的需求。 首先,用户可能有一个普通的C++函数,这个函数不是UFUNCTION,也不是蓝图可调用的。他想在蓝图函数库中的某个蓝图函数里调用这个普通函数,并获取它的返回。但问题是,普通函数如何与蓝图交互呢? 回想一下UE的机制,蓝图只能调用被标记为UFUNCTION的函数,并且需要特定的参数传递方式。普通函数如果没有这些标记,是无法直接被蓝图调用的。所以用户需要一种间接的方法来获取这个普通函数的输出。 可能的解决方案有几个:一是将普通函数封装成一个蓝图可调用的静态函数,这样在蓝图中就可以直接使用。二是如果无法修改原函数,可能需要通过其他方式,比如事件分发器或者中间变量来传递。不过事件分发器可能比较复杂,而中间变量需要考虑作用域和生命周期的问题。 另外,用户可能没有权限修改原来的函数,比如这个函数是第三方库或者引擎内部的,这时候就需要通过适配器模式来封装。或者用户可能误解了问题,其实他需要的是如何从普通函数中获取返回到蓝图中,而不仅仅是蓝图函数库内部的处理。 需要注意的是,用户提到的“在蓝图函数里面获取”,这里的蓝图函数指的是BlueprintFunctionLibrary中的函数,还是蓝图图表中的节点?如果是后者,那么必须通过UFUNCTION暴露的接口才能访问。 可能用户遇到的场景是,他有一个现有的C++函数,返回某个,但因为没有使用UFUNCTION宏,无法直接在蓝图中调用。因此,他需要在蓝图函数库中创建一个包装函数,调用这个普通函数,并将结果通过输出参数或返回传递给蓝图。 这时候需要指导用户如何正确地将普通函数封装到蓝图可调用的函数中,并确保参数正确传递。比如,将普通函数的返回作为UFUNCTION的返回参数,或者通过输出参数传递。 同时,用户可能遇到的错误包括未正确声明UFUNCTION,参数类型不被蓝图支持,或者引用传递的问题。需要提醒用户检查这些点,并确保函数在正确的类中定义,比如BlueprintFunctionLibrary的子类。 另外,用户可能没有意识到,即使普通函数不是静态的,只要在蓝图库中创建一个静态的包装函数,也可以访问实例对象,但这可能需要传递对象引用作为参数,或者确保函数是静态的且不依赖实例数据。 总结下来,解决方案应该是创建一个蓝图可调用的静态函数,内部调用普通函数,并将结果通过输出参数或返回返回给蓝图。需要详细说明步骤,包括如何修改函数签名,添加UFUNCTION宏,处理参数等。同时,要提醒用户注意引用类型和UPARAM标记的使用,以及可能的错误排查步骤。</think>在Unreal Engine 5中,若需在**蓝图函数库的静态函数**中获取**非蓝图函数(普通C++函数)**的输出,需通过中间层进行数据传递。以下是具体实现方案: --- ### 核心思路 1. **普通函数与蓝图的隔离性** 非`UFUNCTION`标记的普通C++函数无法直接与蓝图交互,需通过包装层桥接 2. **间接传策略** 在`BlueprintFunctionLibrary`中创建**中转函数**,内部调用目标函数后传递结果 --- ### 分步解决方案 #### 情况一:可修改目标函数代码(推荐) 若目标函数可被修改,直接将其改造为蓝图可调用函数: ```cpp // 原始普通函数 float NativeCalculate(float A, float B) { return A * B; } // 包装成蓝图可调用函数 UFUNCTION(BlueprintCallable, Category="Math") static float BP_CalculateProduct(float A, float B) { return NativeCalculate(A, B); // 直接调用原始函数 } ``` #### 情况二:无法修改目标函数(第三方/引擎代码) 通过中间变量传递结果: ```cpp // 在BlueprintLibrary类中声明 UFUNCTION(BlueprintCallable, Category="DataBridge") static void FetchNativeResult(UPARAM(ref) float& OutValue) { OutValue = ThirdParty::GetSecretNumber(); // 调用不可修改的普通函数 } ``` --- ### 完整代码示例 ```cpp // MyBlueprintLibrary.h UCLASS() class MYPROJECT_API UMyBlueprintLibrary : public UBlueprintFunctionLibrary { GENERATED_BODY() public: // 包装不可修改的普通函数 UFUNCTION(BlueprintCallable, Category="Custom", meta=(DisplayName="GetPhysicsValue")) static void GetPhysicsResult(UPARAM(ref) float& OutResult); }; // MyBlueprintLibrary.cpp void UMyBlueprintLibrary::GetPhysicsResult(float& OutResult) { // 假设这是无法修改的普通函数 OutResult = FMath::RandRange(0.0f, 100.0f); } ``` --- ### 蓝图端使用方式 1. 在蓝图中调用包装函数节点 2. 输出参数会自动显示为节点的输出引脚 3. 通过`SET`节点将结果存入蓝图变量 ![蓝图节点示意图:包含带有输出引脚的函数节点](https://via.placeholder.com/300x150/EEE/000?text=OutputPin+Example) --- ### 高级技巧:多返回处理 若需返回复杂数据,可使用自定义结构体: ```cpp // 定义数据结构 USTRUCT(BlueprintType) struct FAdvancedResult { GENERATED_BODY() UPROPERTY(BlueprintReadWrite) float Value1; UPROPERTY(BlueprintReadWrite) int32 Value2; }; // 包装函数 UFUNCTION(BlueprintCallable) static void GetComplexResult(FAdvancedResult& OutData) { OutData.Value1 = NativeFuncA(); OutData.Value2 = NativeFuncB(); } ``` --- ### 常见问题排查表 | 现象 | 检查点 | 解决方案 | |------|--------|----------| | 无输出引脚 | 1. 参数是否为引用类型(`&`)<br>2. 是否添加`UPARAM(ref)` | 修改参数声明为`int32& OutVal` | | 编译错误 | 1. 函数是否声明为`static`<br>2. 类是否继承自`UBlueprintFunctionLibrary` | 检查类继承关系 | | 数据异常 | 1. 类型是否匹配(如`float`与`double`)<br>2. 单位制是否统一 | 添加类型转换节点 | --- ### 性能优化建议 1. **避免高频调用** 普通函数若涉及复杂计算,建议通过异步任务处理 2. **数据缓存机制** 对于不变的计算结果,使用`BlueprintThreadSafe`缓存: ```cpp UFUNCTION(BlueprintCallable, BlueprintThreadSafe) static float GetCachedResult() { static float CachedValue = ComputeHeavyTask(); return CachedValue; } ``` 通过这种封装策略,可在保持原有代码结构的同时实现蓝图与原生C++的无缝数据交互。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值