UE4运用C++和框架开发坦克大战教程笔记(十五)(第46~48集)
- 46. 批量加载 UClass 功能
- 测试批量加载多个同类 UClass 资源
- 47. 创建单个资源对象
- 测试加载并创建单个 UClass 资源对象
- 48. 创建同类资源对象
46. 批量加载 UClass 功能
逻辑和批量加载同类 UObject 资源的逻辑差不多。区别在 DealClassKindLoadStack()
内,如果已经有资源率先加载完成了,那后续资源加载的途中我们想让已经加载好的资源执行额外的处理逻辑(比如让它每帧生成),我们就需要补充额外的判断条件,即判断其是否第一次生成完毕。
DDWealth.h
// 加载批量 Class
struct ClassKindLoadNode;UCLASS()
class DATADRIVEN_API UDDWealth : public UObject, public IDDMM
{GENERATED_BODY()protected:// 处理批量加载 Class 节点的方法void DealClassKindLoadStack();protected:TArray<ClassKindLoadNode*> ClassKindLoadStack;
};
DDWealth.cpp
struct ClassKindLoadNode
{// 加载句柄TSharedPtr<FStreamableHandle> WealthHandle;// 没有加载的资源TArray<FClassWealthEntry*> UnLoadWealthEntry;// 已经加载的资源的数组TArray<FClassWealthEntry*> LoadWealthEntry;// 请求对象名FName ObjectName;// 回调方法名FName FunName;// 构造函数ClassKindLoadNode(TSharedPtr<FStreamableHandle> InWealthHandle, TArray<FClassWealthEntry*> InUnLoadWealthEntry, TArray<FClassWealthEntry*>& InLoadWealthEntry, FName InObjectName, FName InFunName){WealthHandle = InWealthHandle;UnLoadWealthEntry = InUnLoadWealthEntry;LoadWealthEntry = InLoadWealthEntry;ObjectName = InObjectName;FunName = InFunName;}
};void UDDWealth::WealthTick(float DeltaSeconds)
{DealClassKindLoadStack();
}void UDDWealth::LoadClassWealthKind(FName WealthKind, FName ObjectName, FName FunName)
{TArray<FClassWealthEntry*> WealthEntryGroup = GetClassKindEntry(WealthKind);// 如果数量为 0if (WealthEntryGroup.Num() == 0) {DDH::Debug() << ObjectName << " Get Null WealthKind : " << WealthKind << DDH::Endl();return;}// 判断资源可用性for (int i = 0; i < WealthEntryGroup.Num(); ++i) {if (!WealthEntryGroup[i]->WealthPtr.ToSoftObjectPath().IsValid()) {DDH::Debug() << ObjectName << " Get Not Valid in Kind : " << WealthKind << " For Name : " << WealthEntryGroup[i]->WealthName << DDH::Endl();return;}}// 未加载资源序列TArray<FClassWealthEntry*> UnLoadWealthEntry;// 已加载资源序列TArray<FClassWealthEntry*> LoadWealthEntry;// 分类保存for (int i = 0; i < WealthEntryGroup.Num(); ++i) {if (WealthEntryGroup[i]->WealthClass)LoadWealthEntry.Push(WealthEntryGroup[i]);elseUnLoadWealthEntry.Push(WealthEntryGroup[i]);}// 判断所有资源是否都已经加载if (UnLoadWealthEntry.Num() == 0) {// 填充参数TArray<FName> NameGroup;TArray<UClass*> WealthGroup;for (int i = 0; i < LoadWealthEntry.Num(); ++i) {NameGroup.Push(LoadWealthEntry[i]->WealthName);WealthGroup.Push(LoadWealthEntry[i]->WealthClass);}// 返回资源给请求对象BackClassWealthKind(ModuleIndex, ObjectName, FunName, NameGroup, WealthGroup);}else {// 获取未加载资源路径数组TArray<FSoftObjectPath> WealthPaths;for (int i = 0; i < UnLoadWealthEntry.Num(); ++i)WealthPaths.Push(UnLoadWealthEntry[i]->WealthPtr.ToSoftObjectPath());// 进行异步加载获取句柄TSharedPtr<FStreamableHandle> WealthHandle = WealthLoader.RequestAsyncLoad(WealthPaths);// 添加新的加载节点ClassKindLoadStack.Push(new ClassKindLoadNode(WealthHandle, UnLoadWealthEntry, LoadWealthEntry, ObjectName, FunName));}
}void UDDWealth::DealClassKindLoadStack()
{// 定义已完成加载节点序列TArray<ClassKindLoadNode*> CompleteStack;for (int i = 0; i < ClassKindLoadStack.Num(); ++i) {// 判断第一次加载完成,WealthHandle 已经加载完成,UnLoadWealthEntry 数量大于 0if (ClassKindLoadStack[i]->WealthHandle->HasLoadCompleted() && ClassKindLoadStack[i]->UnLoadWealthEntry.Num() > 0) {// 如果已经加载完成,设置未加载序列的资源指针for (int j = 0; j < ClassKindLoadStack[i]->UnLoadWealthEntry.Num(); ++j)ClassKindLoadStack[i]->UnLoadWealthEntry[j]->WealthClass = Cast<UClass>(ClassKindLoadStack[i]->UnLoadWealthEntry[j]->WealthPtr.ToSoftObjectPath().ResolveObject());// 将未加载完成序列里的资源填充到已加载资源序列ClassKindLoadStack[i]->LoadWealthEntry.Append(ClassKindLoadStack[i]->UnLoadWealthEntry);// 清空 UnLoadWealthEntryClassKindLoadStack[i]->UnLoadWealthEntry.Empty();}// 如果未加载序列为 0,说明已经加载完成if (ClassKindLoadStack[i]->UnLoadWealthEntry.Num() == 0) {// 加载 UClass 或者直接生成资源的情况来处理// 设置反射参数TArray<FName> NameGroup;TArray<UClass*> WealthGroup;for (int j = 0; j < ClassKindLoadStack[i]->LoadWealthEntry.Num(); ++j) {NameGroup.Push(ClassKindLoadStack[i]->LoadWealthEntry[j]->WealthName);WealthGroup.Push(ClassKindLoadStack[i]->LoadWealthEntry[j]->WealthClass);}// 返回资源给请求对象BackClassWealthKind(ModuleIndex, ClassKindLoadStack[i]->ObjectName, ClassKindLoadStack[i]->FunName, NameGroup, WealthGroup);// 添加该节点到已完成序列CompleteStack.Push(ClassKindLoadStack[i]);}}// 清空已完成节点for (int i = 0; i < CompleteStack.Num(); ++i) {ClassKindLoadStack.Remove(CompleteStack[i]);delete CompleteStack[i];}
}
测试批量加载多个同类 UClass 资源
接下来是验证环节,我们打算让多个 Actor 生成在场景中,并且为了让它们不会挤到一块,所以每次生成的时候将位置偏移一点。
WealthCallObject.h
public:// 回调函数UFUNCTION()void LoadKindClass(TArray<FName> BackNames, TArray<UClass*> BackWealths);public:// 生成的偏移量UPROPERTY(EditAnywhere)float OffsetValue;
WealthCallObject.cpp
void UWealthCallObject::DDLoading()
{// 测试完毕后记得注释掉LoadClassWealthKind("ViewActor", "LoadKindClass");
}void UWealthCallObject::LoadKindClass(TArray<FName> BackNames, TArray<UClass*> BackWealths)
{for (int i = 0; i < BackWealths.Num(); ++i) {DDH::Debug() << BackNames[i] << DDH::Endl();GetDDWorld()->SpawnActor<AActor>(BackWealths[i], ViewTrans.GetLocation() + FVector(OffsetValue * i, 0.f, 0.f), FQuat::Identity.Rotator());}
}
编译后,在 Blueprint 文件夹下创建一个 ViewActor 文件夹,将 ViewActor1 放进去,并复制两个,分别取名为 ViewActor2 和 ViewActor3。给它俩换一下网格体模型。
给 PlayerData 里再配置两个 Class 资源数据:
打开 WealthCallObject 的蓝图,设置 Offset Value 为 150。
运行游戏,可见左上角输出了 3 个 Class 资源的名字,场景内也出现了它们的实例。
在第一次运行后,在 Deal{xxx}LoadStack()
方法里会给加载节点里的 UObject*
/ UClass*
赋值,它们就不为空了,也就不会进行异步加载,为了让它每次都像第一次运行那样(为了方便测试异步加载无误),我们要修改一下代码,让它在编辑器运行时每次都清空 WealthObject 和 WealthClass。这样就以后打包完游戏就不会自动清空。
DDWealth.cpp
void UDDWealth::WealthBeginPlay()
{for (int i = 0; i < WealthData.Num(); ++i) {// ... 省略#if WITH_EDITOR // 循环设置 WealthObject 和 WealthClass 为空,目的在于每次从编辑器启动游戏时,资源 Asset 的状态都重置for (int j = 0; j < WealthData[i]->ObjectWealthData.Num(); ++j)WealthData[i]->ObjectWealthData[j].WealthObject = NULL;for (int j = 0; j < WealthData[i]->ClassWealthData.Num(); ++j)WealthData[i]->ClassWealthData[j].WealthClass = NULL;
#endif}
}
47. 创建单个资源对象
我们先前写的逻辑都是加载资源然后将其返回给请求者,接下来我们打算实现:加载 UClass 资源并创建对象后,将对象返回给请求者。
下图截取自梁迪老师的 DataDriven 文档:
创建多个对象的方法里,每帧都会创建一个对象,创建足够数量的对象后才会将所有的对象返回给请求对象。
这节课我们先实现创建单个资源对象的功能。
DDWealth.h
public:// 创建一个对象实例void BuildSingleClassWealth(EWealthType WealthType, FName WealthName, FName ObjectName, FName FunName, FTransform SpawnTransform);protected:// 生成三种资源对象的反射回调函数DDOBJFUNC_TWO(BackObject, FName, BackName, UObject*, BackObject);DDOBJFUNC_TWO(BackActor, FName, BackName, AActor*, BackActor);DDOBJFUNC_TWO(BackWidget, FName, BackName, UUserWidget*, BackWidget);
DDWealth.cpp
// 给 UClass 加载节点补充另外的内容,以便支持对象创建
struct ClassSingleLoadNode
{TSharedPtr<FStreamableHandle> WealthHandle;FClassWealthEntry* WealthEntry;FName ObjectName;FName FunName;// 生成位置FTransform SpawnTransform;// 是否只加载 UClass 资源bool IsLoadClass;ClassSingleLoadNode(TSharedPtr<FStreamableHandle> InWealthHandle, FClassWealthEntry* InWealthEntry, FName InObjectName, FName InFunName){WealthHandle = InWealthHandle;WealthEntry = InWealthEntry;ObjectName = InObjectName;FunName = InFunName;IsLoadClass = true; // 添加}// 另一个构造函数ClassSingleLoadNode(TSharedPtr<FStreamableHandle> InWealthHandle, FClassWealthEntry* InWealthEntry, FName InObjectName, FName InFunName, FTransform InSpawnTransform){WealthHandle = InWealthHandle;WealthEntry = InWealthEntry;ObjectName = InObjectName;FunName = InFunName;SpawnTransform = InSpawnTransform;IsLoadClass = false;}
};// 给处理方法增加判断,是仅仅加载资源还是创建对象
void UDDWealth::DealClassSingleLoadStack()
{TArray<ClassSingleLoadNode*> CompleteStack;for (int i = 0; i < ClassSingleLoadStack.Num(); ++i) {if (ClassSingleLoadStack[i]->WealthHandle->HasLoadCompleted()) {ClassSingleLoadStack[i]->WealthEntry->WealthClass = Cast<UClass>(ClassSingleLoadStack[i]->WealthEntry->WealthPtr.ToSoftObjectPath().ResolveObject());// 判断是否生成对象if (ClassSingleLoadStack[i]->IsLoadClass) {// 返回资源给对象BackClassWealth(ModuleIndex, ClassSingleLoadStack[i]->ObjectName, ClassSingleLoadStack[i]->FunName, ClassSingleLoadStack[i]->WealthEntry->WealthName, ClassSingleLoadStack[i]->WealthEntry->WealthClass);}else {// 生成相应类型的对象并且传递对象到请求者if (ClassSingleLoadStack[i]->WealthEntry->WealthType == EWealthType::Object) {UObject* InstObject = NewObject<UObject>(this, ClassSingleLoadStack[i]->WealthEntry->WealthClass);InstObject->AddToRoot();BackObject(ModuleIndex, ClassSingleLoadStack[i]->ObjectName, ClassSingleLoadStack[i]->FunName, ClassSingleLoadStack[i]->WealthEntry->WealthName, InstObject);}else if (ClassSingleLoadStack[i]->WealthEntry->WealthType == EWealthType::Actor) {AActor* InstActor = GetDDWorld()->SpawnActor<AActor>(ClassSingleLoadStack[i]->WealthEntry->WealthClass, ClassSingleLoadStack[i]->SpawnTransform);BackActor(ModuleIndex, ClassSingleLoadStack[i]->ObjectName, ClassSingleLoadStack[i]->FunName, ClassSingleLoadStack[i]->WealthEntry->WealthName, InstActor);}else if (ClassSingleLoadStack[i]->WealthEntry->WealthType == EWealthType::Widget) {UUserWidget* InstWidget = CreateWidget<UUserWidget>(GetDDWorld(), ClassSingleLoadStack[i]->WealthEntry->WealthClass);// 避免回收GCWidgetGroup.Push(InstWidget);BackWidget(ModuleIndex, ClassSingleLoadStack[i]->ObjectName, ClassSingleLoadStack[i]->FunName, ClassSingleLoadStack[i]->WealthEntry->WealthName, InstWidget);}}CompleteStack.Push(ClassSingleLoadStack[i]);}}for (int i = 0; i < CompleteStack.Num(); ++i) {ClassSingleLoadStack.Remove(CompleteStack[i]);delete CompleteStack[i];}
}void UDDWealth::BuildSingleClassWealth(EWealthType WealthType, FName WealthName, FName ObjectName, FName FunName, FTransform SpawnTransform)
{// 获取对应的资源结构体FClassWealthEntry* WealthEntry = GetClassSingleEntry(WealthName);// 如果为空if (!WealthEntry) {DDH::Debug() << ObjectName << " Get Null Wealth : " << WealthName << DDH::Endl();return;}// 如果资源不可用if (!WealthEntry->WealthPtr.ToSoftObjectPath().IsValid()) {DDH::Debug() << ObjectName << " Get UnValid Wealth : " << WealthName << DDH::Endl();return;}// 资源类型是否匹配if (WealthEntry->WealthType != WealthType) {DDH::Debug() << ObjectName << " Get Error Type : " << DDH::Endl();return;}// 如果资源已经加载if (WealthEntry->WealthClass) {// 根据类型来执行不同生成逻辑并且传递对象到请求者if (WealthType == EWealthType::Object) {UObject* InstObject = NewObject<UObject>(this, WealthEntry->WealthClass);InstObject->AddToRoot();// 传递对象到请求者BackObject(ModuleIndex, ObjectName, FunName, WealthName, InstObject);}else if (WealthType == EWealthType::Actor) {AActor* InstActor = GetDDWorld()->SpawnActor<AActor>(WealthEntry->WealthClass, SpawnTransform);BackActor(ModuleIndex, ObjectName, FunName, WealthName, InstActor);}else if (WealthType == EWealthType::Widget) {UUserWidget* InstWidget = CreateWidget<UUserWidget>(GetDDWorld(), WealthEntry->WealthClass);// 避免回收GCWidgetGroup.Push(InstWidget);BackWidget(ModuleIndex, ObjectName, FunName, WealthName, InstWidget);}}else {// 异步加载,获取加载句柄TSharedPtr<FStreamableHandle> WealthHandle = WealthLoader.RequestAsyncLoad(WealthEntry->WealthPtr.ToSoftObjectPath());// 创建新加载节点ClassSingleLoadStack.Push(new ClassSingleLoadNode(WealthHandle, WealthEntry, ObjectName, FunName, SpawnTransform));}
}
补全 DDWealth – DDModule – DDOO – 对象 的调用链。
DDModule.h
public: // 创建一个对象实例void BuildSingleClassWealth(EWealthType WealthType, FName WealthName, FName ObjectName, FName FunName, FTransform SpawnTransform);
DDModule.cpp
void UDDModule::BuildSingleClassWealth(EWealthType WealthType, FName WealthName, FName ObjectName, FName FunName, FTransform SpawnTransform)
{Wealth->BuildSingleClassWealth(WealthType, WealthName, ObjectName, FunName, SpawnTransform);
}
DDOO 有些不一样,它需要额外判断是否需要传入生成位置,这是专门为 Actor 准备的。
DDOO.h
protected:// 创建一个对象实例// 给 Object 和 Widget 用的void BuildSingleClassWealth(EWealthType WealthType, FName WealthName, FName FunName);// 给 Actor 用的void BuildSingleClassWealth(EWealthType WealthType, FName WealthName, FName FunName, FTransform SpawnTransform);
DDOO.cpp
void IDDOO::BuildSingleClassWealth(EWealthType WealthType, FName WealthName, FName FunName)
{IModule->BuildSingleClassWealth(WealthType, WealthName, GetObjectName(), FunName, FTransform::Identity);
}void IDDOO::BuildSingleClassWealth(EWealthType WealthType, FName WealthName, FName FunName, FTransform SpawnTransform)
{IModule->BuildSingleClassWealth(WealthType, WealthName, GetObjectName(), FunName, SpawnTransform);
}
测试加载并创建单个 UClass 资源对象
我们打算只测试创建一个 Actor 资源对象,并且让它一直旋转。
WealthCallObject.h
public:virtual void DDTick(float DeltaSeconds) override;// 回调方法UFUNCTION()void BuildActor(FName BackName, AActor* BackActor);public:// 保存返回的 ActorAActor* SingleActor;
WealthCallObject.cpp
void UWealthCallObject::DDLoading()
{Super::DDLoading();IsAllowTickEvent = true; // 实际上开启帧函数的bool值这个最好放在 DDInit()// ... 省略// 测试完毕后记得注释掉BuildSingleClassWealth(EWealthType::Actor, "ViewActor1", "BuildActor", ViewTrans);
}void UWealthCallObject::DDTick(float DeltaSeconds)
{Super::DDTick(DeltaSeconds);if (SingleActor) {SingleActor->AddActorWorldRotation(FRotator(1.f, 0.f, 0.f));}
}void UWealthCallObject::BuildActor(FName BackName, AActor* BackActor)
{DDH::Debug() << BackName << DDH::Endl();SingleActor = BackActor;
}
编译后运行游戏,可以看见左上角输出了 ViewActor1,场景中生成了 ViewActor1,并且它一直在旋转。说明加载并创建 UClass 对象的逻辑写好了。
顺便打开 PlayerData 将 AutoActorData 下的两个对象去掉,免得在场景里占位置。
48. 创建同类资源对象
接下来实现创建多个同种类名(WealthKind)的资源对象实例后返回给申请者。
DDWealth.h 里的反射回调函数的声明宏,调整一下原本第一个参数的命名,加一个 Single
,避免与最后一个参数重名。并且 .cpp 里对应的调用语句也要跟着修改。
DDWealth.h
public:// 创建同资源种类名的对象实例,同种类名下的每个资源链接创建一个对象实例void BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName ObjectName, FName FunName, TArray<FTransform> SpawnTransforms);protected:// 给之前的生成单个对象的反射回调函数,函数名后添加 “Single”DDOBJFUNC_TWO(BackObjectSingle, FName, BackName, UObject*, BackObject);// 添加同种类 Object 的反射回调函数DDOBJFUNC_TWO(BackObjectKind, TArray<FName>, BackNames, TArray<UObject*>, BackObjects);DDOBJFUNC_TWO(BackActorSingle, FName, BackName, AActor*, BackActor);// 添加同种类 Actor 的反射回调函数DDOBJFUNC_TWO(BackActorKind, TArray<FName>, BackNames, TArray<AActor*>, BackActors);DDOBJFUNC_TWO(BackWidgetSingle, FName, BackName, UUserWidget*, BackWidget);// 添加同种类 Widget 的反射回调函数DDOBJFUNC_TWO(BackWidgetKind, TArray<FName>, BackNames, TArray<UUserWidget*>, BackWidgets);
DDWealth.cpp
struct ClassKindLoadNode
{TSharedPtr<FStreamableHandle> WealthHandle;TArray<FClassWealthEntry*> UnLoadWealthEntry;TArray<FClassWealthEntry*> LoadWealthEntry;FName ObjectName;FName FunName;// 多个生成位置TArray<FTransform> SpawnTransforms;// 是否只加载 Classbool IsLoadClass;// 保存生成的对象与名字TArray<FName> NameGroup;TArray<UObject*> ObjectGroup;TArray<AActor*> ActorGroup;TArray<UUserWidget*> WidgetGroup;ClassKindLoadNode(TSharedPtr<FStreamableHandle> InWealthHandle, TArray<FClassWealthEntry*> InUnLoadWealthEntry, TArray<FClassWealthEntry*>& InLoadWealthEntry, FName InObjectName, FName InFunName){WealthHandle = InWealthHandle;UnLoadWealthEntry = InUnLoadWealthEntry;LoadWealthEntry = InLoadWealthEntry;ObjectName = InObjectName;FunName = InFunName;IsLoadClass = true; // 补充}// 创建 UClass 对象所使用的构造函数ClassKindLoadNode(TSharedPtr<FStreamableHandle> InWealthHandle, TArray<FClassWealthEntry*> InUnLoadWealthEntry, TArray<FClassWealthEntry*>& InLoadWealthEntry, FName InObjectName, FName InFunName, TArray<FTransform> InSpawnTransforms){WealthHandle = InWealthHandle;UnLoadWealthEntry = InUnLoadWealthEntry;LoadWealthEntry = InLoadWealthEntry;ObjectName = InObjectName;FunName = InFunName;SpawnTransforms = InSpawnTransforms;IsLoadClass = false; }
};void UDDWealth::DealClassSingleLoadStack()
{// ... 省略else {if (ClassSingleLoadStack[i]->WealthEntry->WealthType == EWealthType::Object) {UObject* InstObject = NewObject<UObject>(this, ClassSingleLoadStack[i]->WealthEntry->WealthClass);InstObject->AddToRoot();// 更改BackObjectSingle(ModuleIndex, ClassSingleLoadStack[i]->ObjectName, ClassSingleLoadStack[i]->FunName, ClassSingleLoadStack[i]->WealthEntry->WealthName, InstObject);}else if (ClassSingleLoadStack[i]->WealthEntry->WealthType == EWealthType::Actor) {AActor* InstActor = GetDDWorld()->SpawnActor<AActor>(ClassSingleLoadStack[i]->WealthEntry->WealthClass, ClassSingleLoadStack[i]->SpawnTransform);// 更改BackActorSingle(ModuleIndex, ClassSingleLoadStack[i]->ObjectName, ClassSingleLoadStack[i]->FunName, ClassSingleLoadStack[i]->WealthEntry->WealthName, InstActor);}else if (ClassSingleLoadStack[i]->WealthEntry->WealthType == EWealthType::Widget) {UUserWidget* InstWidget = CreateWidget<UUserWidget>(GetDDWorld(), ClassSingleLoadStack[i]->WealthEntry->WealthClass);GCWidgetGroup.Push(InstWidget);// 更改BackWidgetSingle(ModuleIndex, ClassSingleLoadStack[i]->ObjectName, ClassSingleLoadStack[i]->FunName, ClassSingleLoadStack[i]->WealthEntry->WealthName, InstWidget);}}CompleteStack.Push(ClassSingleLoadStack[i]);}}// ... 省略
}void UDDWealth::DealClassKindLoadStack()
{TArray<ClassKindLoadNode*> CompleteStack;for (int i = 0; i < ClassKindLoadStack.Num(); ++i) {// 补充判断条件,句柄可用才继续执行加载if (ClassKindLoadStack[i]->WealthHandle.IsValid() && ClassKindLoadStack[i]->WealthHandle->HasLoadCompleted() && ClassKindLoadStack[i]->UnLoadWealthEntry.Num() > 0) {// ... 省略}if (ClassKindLoadStack[i]->UnLoadWealthEntry.Num() == 0) {// 将原来的代码多套一层 if 判断,确定是否要生成对象// 加载 UClass 或者直接生成资源的情况来处理if(ClassKindLoadStack[i]->IsLoadClass) {TArray<FName> NameGroup;TArray<UClass*> WealthGroup;for (int j = 0; j < ClassKindLoadStack[i]->LoadWealthEntry.Num(); ++j) {NameGroup.Push(ClassKindLoadStack[i]->LoadWealthEntry[j]->WealthName);WealthGroup.Push(ClassKindLoadStack[i]->LoadWealthEntry[j]->WealthClass);}BackClassWealthKind(ModuleIndex, ClassKindLoadStack[i]->ObjectName, ClassKindLoadStack[i]->FunName, NameGroup, WealthGroup);CompleteStack.Push(ClassKindLoadStack[i]);} else { // 如果要生成对象// 从已加载的资源数组中取出第一个FClassWealthEntry* WealthEntry = ClassKindLoadStack[i]->LoadWealthEntry[0];// 移除出序列ClassKindLoadStack[i]->LoadWealthEntry.RemoveAt(0);// 根据资源类型生成对象if (WealthEntry->WealthType == EWealthType::Object) {UObject* InstObject = NewObject<UObject>(this, WealthEntry->WealthClass);InstObject->AddToRoot();// 添加找参数数组ClassKindLoadStack[i]->NameGroup.Push(WealthEntry->WealthName);ClassKindLoadStack[i]->ObjectGroup.Push(InstObject);// 判断是否生成了全部的对象if (ClassKindLoadStack[i]->LoadWealthEntry.Num() == 0) {// 给请求者传递生成的对象BackObjectKind(ModuleIndex, ClassKindLoadStack[i]->ObjectName, ClassKindLoadStack[i]->FunName, ClassKindLoadStack[i]->NameGroup, ClassKindLoadStack[i]->ObjectGroup);// 添加到完成序列CompleteStack.Push(ClassKindLoadStack[i]);}}else if (WealthEntry->WealthType == EWealthType::Actor) {// 获取生成位置FTransform SpawnTransform = ClassKindLoadStack[i]->SpawnTransforms.Num() == 1 ? ClassKindLoadStack[i]->SpawnTransforms[0] : ClassKindLoadStack[i]->SpawnTransforms[ClassKindLoadStack[i]->ActorGroup.Num()];// 生成对象AActor* InstActor = GetDDWorld()->SpawnActor<AActor>(WealthEntry->WealthClass, SpawnTransform);// 添加找参数数组ClassKindLoadStack[i]->NameGroup.Push(WealthEntry->WealthName);ClassKindLoadStack[i]->ActorGroup.Push(InstActor);// 判断是否生成了全部的对象if (ClassKindLoadStack[i]->LoadWealthEntry.Num() == 0) {// 给请求者传递生成的对象BackActorKind(ModuleIndex, ClassKindLoadStack[i]->ObjectName, ClassKindLoadStack[i]->FunName, ClassKindLoadStack[i]->NameGroup, ClassKindLoadStack[i]->ActorGroup);// 添加到完成序列CompleteStack.Push(ClassKindLoadStack[i]);}}else if (WealthEntry->WealthType == EWealthType::Widget) {UUserWidget* InstWidget = CreateWidget<UUserWidget>(GetDDWorld(), WealthEntry->WealthClass);// 避免回收GCWidgetGroup.Push(InstWidget);// 添加找参数数组ClassKindLoadStack[i]->NameGroup.Push(WealthEntry->WealthName);ClassKindLoadStack[i]->WidgetGroup.Push(InstWidget);// 判断是否生成了全部的对象if (ClassKindLoadStack[i]->LoadWealthEntry.Num() == 0) {// 给请求者传递生成的对象BackWidgetKind(ModuleIndex, ClassKindLoadStack[i]->ObjectName, ClassKindLoadStack[i]->FunName, ClassKindLoadStack[i]->NameGroup, ClassKindLoadStack[i]->WidgetGroup);// 添加到完成序列CompleteStack.Push(ClassKindLoadStack[i]);}}} }}// ... 省略
}void UDDWealth::BuildSingleClassWealth(EWealthType WealthType, FName WealthName, FName ObjectName, FName FunName, FTransform SpawnTransform)
{// ... 省略if (WealthEntry->WealthClass) {if (WealthType == EWealthType::Object) {UObject* InstObject = NewObject<UObject>(this, WealthEntry->WealthClass);InstObject->AddToRoot();// 更改BackObjectSingle(ModuleIndex, ObjectName, FunName, WealthName, InstObject);}else if (WealthType == EWealthType::Actor) {AActor* InstActor = GetDDWorld()->SpawnActor<AActor>(WealthEntry->WealthClass, SpawnTransform);// 更改BackActorSingle(ModuleIndex, ObjectName, FunName, WealthName, InstActor);}else if (WealthType == EWealthType::Widget) {UUserWidget* InstWidget = CreateWidget<UUserWidget>(GetDDWorld(), WealthEntry->WealthClass);GCWidgetGroup.Push(InstWidget);// 更改BackWidgetSingle(ModuleIndex, ObjectName, FunName, WealthName, InstWidget);}}// ... 省略
}void UDDWealth::BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName ObjectName, FName FunName, TArray<FTransform> SpawnTransforms)
{TArray<FClassWealthEntry*> WealthEntryGroup = GetClassKindEntry(WealthKind);// 为 0 则说明不存在该资源种类if (WealthEntryGroup.Num() == 0) {DDH::Debug() << ObjectName << " Get Null WealthKind : " << WealthKind << DDH::Endl();return;}for (int i = 0; i < WealthEntryGroup.Num(); ++i) {// 资源可用性if (!WealthEntryGroup[i]->WealthPtr.ToSoftObjectPath().IsValid()) {DDH::Debug() << ObjectName << " Get Not Valid In Kind : " << WealthKind << " For Name : " << WealthEntryGroup[i]->WealthName << DDH::Endl();return;}// 如果资源类型不匹配if (WealthEntryGroup[i]->WealthType != WealthType) {DDH::Debug() << ObjectName << " Get Error Type In Kind : " << WealthKind << " For Name : " << WealthEntryGroup[i]->WealthName << DDH::Endl();return;}}// 对于 Actor,有多少个对象就有多少个 Transform;对于 Object 和 Widget 则只有一个 Transform// 判断 Transform 数组是否为 1 或者是否为 WealthEntryGroup 的数量if (WealthType == EWealthType::Actor && SpawnTransforms.Num() != 1 && SpawnTransforms.Num() != WealthEntryGroup.Num()) {DDH::Debug() << ObjectName << " Send Error Spawn Count : " << WealthKind << DDH::Endl();return;}// 未加载的资源链接TArray<FClassWealthEntry*> UnLoadWealthEntry;// 已加载的资源链接TArray<FClassWealthEntry*> LoadWealthEntry;// 资源分类for (int i = 0; i < WealthEntryGroup.Num(); ++i) {if (WealthEntryGroup[i]->WealthClass)LoadWealthEntry.Push(WealthEntryGroup[i]);elseUnLoadWealthEntry.Push(WealthEntryGroup[i]);}// 声明一个加载句柄TSharedPtr<FStreamableHandle> WealthHandle;// 如果有未加载的资源if (UnLoadWealthEntry.Num() > 0) {// 获取资源路径TArray<FSoftObjectPath> WealthPaths;for (int i = 0; i < UnLoadWealthEntry.Num(); ++i)WealthPaths.Push(UnLoadWealthEntry[i]->WealthPtr.ToSoftObjectPath());// 获取加载句柄WealthHandle = WealthLoader.RequestAsyncLoad(WealthPaths);}// 创建帧处理的节点ClassKindLoadStack.Push(new ClassKindLoadNode(WealthHandle, UnLoadWealthEntry, LoadWealthEntry, ObjectName, FunName, SpawnTransforms));
}
剩余部分(补全调用链与测试功能)留到下一节课。