当前位置:   article > 正文

UE5 通过反射机制为指定的类添加成员变量或函数_ue property 初始化

ue property 初始化

        本文聚焦如何在不改变指定类源码的前提下,利用UE反射机制为该类添加UPROPERTYUFUNCTION

        首先要说明的是,这个指定的类,必须是UCLASS。因为只有UClass才支持反射。

寻找办法

        我们都知道,蓝图编辑器可以添加变量也可以添加函数。每次编译,蓝图编辑器都会生成一个class,这就给我们带来突破口,去看蓝图编辑器代码不就成了?!

        于是,翻看代码找到了两个有用的接口,它们是UClass::AddCppProperty(FProperty*)UClass::AddFunctionToFunctionMap(UFunction*, FName)。有了这两个接口,我们就可以实现添加UPROPERTYUFUNCTION了。

添加UPROPERTY

        以CameraComponent为例,我们为它添加一个布尔值变量,并让蓝图可以访问。首先,我们要创建一个布尔类型的FProperty,即FBoolProperty。

  1. UClass* SuperClass = UCameraComponent::StaticClass();
  2. UClass* ClassToAddProperty = SuperClass;
  3. FBoolProperty* NewProperty = new FBoolProperty(
  4. ClassToAddProperty,
  5. TEXT("ShowDebug"),
  6. RF_Public
  7. );
  • 这里是直接使用new创建,不用考虑释放的问题,除非你没添加进去
  • 第一个参数是UClass,我们传入CameraComponent类的UClass
  • 第二个参数是变量名称

        新建出来变量后,我们可以像平时写UPROPERTY说明符那样对其进行属性设置,配置该变量的属性。

NewProperty->SetPropertyFlags(CPF_Edit | CPF_BlueprintVisible);

        这里设置的是EditAnywhereBlueprintReadWrite。更多属性Flag,可以阅读头文件ObjectMacros.h内的EPropertyFlags枚举。

        最后,在添加到类之前,还需要调用FProperty的Link函数,对FProperty完成初始化。这一步非常重要,跳过会导致该变量不可用,且会导致UE崩溃。

  1. FArchive ArDummy;
  2. NewProperty->Link(ArDummy);
  3. ClassToAddProperty->AddCppProperty(NewProperty);

        至此,我们已经成功添加了一个UPROPERTY变量到CameraComponent内。

Actor细节面板:

9b109cd42f0c4ca39322067ee2d2ab8b.png

蓝图节点:

51f1a4c7fa5e46b5a1f85ff2c28612ac.png

 添加UFUNCTION

        添加UFUNCTION稍微复杂一点点,本节将实现添加新的UFUNCTION,名为GetCameraName,并且这个函数可以获取到Camera Componentowner Actor的名称。

        首先,UFunction对象是一个UObject,因此使用NewObject来创建对象。

        新建完UFunction对象后,我们对其Flag进行设置,这里设置的是蓝图可调用、公开函数和原生函数等Flag。更多的flag请参考EFunctionFlags的定义。

        设置完函数的flag后,再设置UFunction对象对应的原生函数,此函数必须是静态的,且需要使用DECLARE_FUNCTION宏进行声明。紧接着我们需要对UFunction进行初始化,调用StaticLink、手动接上UClass内的函数链表。

        最后,调用AddFunctionToFunctionMap

  1. UClass* ClassToAddFunction = SuperClass;
  2. const FName FunctionName = "GetCameraName";
  3. UFunction* NewFunc = NewObject<UFunction>(ClassToAddProperty, FunctionName, RF_Public);
  4. NewFunc->FunctionFlags |= FUNC_BlueprintCallable | FUNC_Public | FUNC_Native;
  5. NewFunc->SetNativeFunc(&UMyCameraFunctionLibrary::execGetCameraName);
  6. NewFunc->StaticLink(true);
  7. NewFunc->Next = ClassToAddProperty->Children;
  8. ClassToAddProperty->Children = NewFunc;
  9. ClassToAddProperty->AddFunctionToFunctionMap(NewFunc, FunctionName);

关于原生函数的内部实现,这里不多介绍,可以参考别的大佬所写文章CustomThunk

  1. // 头文件
  2. #pragma once
  3. #include "CoreMinimal.h"
  4. #include "Kismet/BlueprintFunctionLibrary.h"
  5. #include "MyCameraFunctionLibrary.generated.h"
  6. UCLASS()
  7. class VI_PROJECT_API UMyCameraFunctionLibrary : public UBlueprintFunctionLibrary
  8. {
  9. GENERATED_BODY()
  10. public:
  11. DECLARE_FUNCTION(execGetCameraName);
  12. };
  1. // CPP
  2. #include "MyCameraFunctionLibrary.h"
  3. #include "Camera/CameraComponent.h"
  4. DEFINE_FUNCTION(UMyCameraFunctionLibrary::execGetCameraName)
  5. {
  6. P_FINISH;
  7. P_NATIVE_BEGIN;
  8. if (const UCameraComponent* CameraComponent = Cast<UCameraComponent>(Context))
  9. {
  10. if (const AActor* Owner = CameraComponent->GetOwner())
  11. {
  12. const FString ObjName = Owner->GetName();
  13. GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Cyan, ObjName);
  14. }
  15. }
  16. P_NATIVE_END;
  17. }

至此,我们已经完成了反射函数的添加,以下是成果展示:

0c5c4b28ebb442b3af016a7e399016f9.png

运行后能看到屏幕输出了CameraComponent所属Actor的名称:

83f3a396e0344bceb3727199ae7b8bde.png


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/133247
推荐阅读
相关标签
  

闽ICP备14008679号