UE填坑之c++反射获取对象的Enum类型属性值

· C++

 

在C++代码中,要调用蓝图类对象,首先得通过LoadClass获取蓝图类,再通过UClass获取到Actor对象,因为这是一个蓝图创建的Actor,C++代码中只能通过反射来获取或者修改Actor对象的属性值。获取Actor的代码如下:

 

FString PackageName = TEXT("/Game/DAL/Environment/UltraDynamicSky/Blueprints/Ultra_Dynamic_Sky.Ultra_Dynamic_Sky_C");  

FString FileName = TEXT("/Game/DAL/Environment/UltraDynamicSky/Blueprints/Ultra_Dynamic_Sky.assert");    

ArrUDS.Empty(); //ArrUDS是一个TArray类型变量  

UClass* UDSClass = LoadClass<AActor>(nullptr, *PackageName, *FileName);  

if (UDSClass != nullptr)  

{  

UGameplayStatics::GetAllActorsOfClass(CurrentWorld, UDSClass,this->ArrUDS);  

 

对于普通的float, int, double,FString类型的属性,UE都提供了反射类型,类图如下(图片来源知乎): 

broken image

 

      通过FindProperty()方法,可以获取到UClass里的所有属性值,假设有个float类型的属性,

 FProperty* TypeProperty = FindFProperty<FProperty>(Target->GetClass(), VarName); 

if(TypeProperty->IsA(FFloatProperty::StaticClass()) 

{   

FFloatProperty* FloatProperty =CastField( TypeProperty); 

float Value = FloatProperty ->GetPropertyValue_InContainer(Target); 

这里比较坑的是,UE提供了FEnumProperty这种类型,大家以为如果Actor里面的某个属性是UEnum类型的话,返回的应该是FEnumProperty,我开始也是把FProperty转成FEnumProperty,结果发现FEnumProperty并没有GetPropertyValue_InContainer方法来获取属性值,当时有点懵,然后开始看FEnumPropertyde 源码,发现GetUnderlyingProperty方法可以获取FNumericProperty,然后我就试图通过FNumericProperty来获取属性值了,看了FNumericProperty的源代码,各种数值相关的F*Property的继承关系很是眼花缭乱。

 FNumericProperty* NumericProperty =TestEnum->GetUnderlyingProperty(); 

FEnumProperty里面的真实属性值,在看怎么获取属性值,然而,等我运行起来后,发现根本不是FEnumProperty类型,而是一个FByteProperty类型,并附带一个UEnum。 

FProperty 转成FByteProperty来修改属性值了。 

 

if (TypeProperty->IsA(FByteProperty::StaticClass()))  

{  

FByteProperty* ByteProperty = CastField<FByteProperty>(TypeProperty);  

UEnum* Enum = ByteProperty->Enum;  

uint8 Value =ByteProperty->GetPropertyValue_InContainer(Target);    

if (Enum)  

{  

UE_LOG(LogTemp, Display, TEXT("Current Weather Type is %s"), *Enum->GetNameStringByValue(Value));  

UE_LOG(LogTemp, Display, TEXT("New Weather Type is %s"), *Enum->GetNameStringByValue(InValue))  

}    

{  

ByteProperty->SetPropertyValue_InContainer(Target, InValue);  

//get new weather type  

Value =ByteProperty->GetPropertyValue_InContainer(Target);  

if (Enum)  

{  

UE_LOG(LogTemp, Display, TEXT("Current Weather Type is %s"), *Enum->GetNameStringByValue(Value));  

}  

}  

//ByteProperty->SetPropertyValue_InContainer(Target,InValue); // set the value from   

return true; // we can return   

这里就体现出UE类封装的不够完美了,既然提供了FEnumProperty,并且它也是从FProperty派生下来的,那不管内部是怎么实现的,对外提供一个SetPropertyValue_InContainer,GetPropertyValue_InContainer方法,不就是行了吗?内部实现不同,外部接口一致,这才是真正的封装啊。面向对象的基本特性,UE这些人写出来的代码也会犯错。