在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都提供了反射类型,类图如下(图片来源知乎):
通过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这些人写出来的代码也会犯错。