UE4运用C++和框架开发坦克大战教程笔记(十六)(第49~50集)

UE4运用C++和框架开发坦克大战教程笔记(十六)(第49~50集)

49. 创建多个资源对象

补全调用链并测试生成多个同种类名资源对象

上节写好了 DDWealth 里的创建同种类名资源对象的方法,这集开头先来补充完整 DDWealth -- DDModule -- DDOO -- 对象 这条调用链。

DDModule.h

cpp 复制代码
public:

	// 创建同资源种类名的对象实例,同种类名下的每个资源链接创建一个对象实例
	void BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName ObjectName, FName FunName, TArray<FTransform> SpawnTransforms);

DDModule.cpp

cpp 复制代码
void UDDModule::BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName ObjectName, FName FunName, TArray<FTransform> SpawnTransforms)
{
	Wealth->BuildKindClassWealth(WealthType, WealthKind, ObjectName, FunName, SpawnTransforms);
}

对于 DDOO 来说,要根据生成对象的种类类型来区分调用方法。并且也不需要传 ObjectName,因为它自带有。

DDOO.h

cpp 复制代码
protected:

	// 创建同资源种类名的对象实例,同种类名下的每个资源链接创建一个对象实例
	void BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName FunName);
	void BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName FunName, FTransform SpawnTransform);
	void BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName FunName, TArray<FTransform> SpawnTransforms);

DDOO.cpp

cpp 复制代码
// 区分点在于传入多少个 FTransform
// 对 Widget 类型
void IDDOO::BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName FunName)
{
	IModule->BuildKindClassWealth(WealthType, WealthKind, GetObjectName(), FunName, TArray<FTransform>{ FTransform::Identity });
}

// 对 Object 类型
void IDDOO::BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName FunName, FTransform SpawnTransform)
{
	IModule->BuildKindClassWealth(WealthType, WealthKind, GetObjectName(), FunName, TArray<FTransform>{ SpawnTransform });
}

// 对 Actor 类型
void IDDOO::BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName FunName, TArray<FTransform> SpawnTransforms)
{
	IModule->BuildKindClassWealth(WealthType, WealthKind, GetObjectName(), FunName, SpawnTransforms);
}

接下来到 WealthCallObject 里进行验证。我们打算生成 3 个同种类名的对象到场景中,并且让它们一直旋转。

WealthCallObject.h

cpp 复制代码
public:

	// 回调方法
	UFUNCTION()
	void BuildActorKind(TArray<FName> BackNames, TArray<AActor*> BackActors);

public:

	// 存储生成的 Actor
	TArray<AActor*> KindActors;

WealthCallObject.cpp

cpp 复制代码
void UWealthCallObject::DDLoading()
{
	
	
	// 生成 3 个偏移的位置
	TArray<FTransform> SpawnTransforms;
	for (int i = 0; i < 3; ++i) {
		SpawnTransforms.Push(FTransform(ViewTrans.GetLocation() + FVector(OffsetValue * i, 0.f, 0.f)));
	}

	// 测试完毕后注释掉这句
	BuildKindClassWealth(EWealthType::Actor, "ViewActor", "BuildActorKind", SpawnTransforms);
}

void UWealthCallObject::DDTick(float DeltaSeconds)
{
	

	for (int i = 0; i < KindActors.Num(); ++i)
		KindActors[i]->AddActorWorldRotation(FRotator(1.f, 0.f, 0.f));
}

void UWealthCallObject::BuildActorKind(TArray<FName> BackNames, TArray<AActor*> BackActors)
{
	for (int i = 0; i < BackNames.Num(); ++i)
		DDH::Debug() << BackNames[i] << DDH::Endl();
	KindActors = BackActors;
}

编译后,因为我们在 PlayerData 里已经配置好了 3 个 ViewActor 的数据,所以直接运行游戏,可以看到左上角输出了三个对象的名字,并且场景中它们 3 个在旋转。说明批量生成同种类名 Actor 对象的逻辑写好了。

实现创建多个同资源名的对象实例

前面实现了创建同种类名(WealthKind)的多个资源对象,现在我们来实现创建多个同资源名(WealthName)的资源对象。

DDWealth.h

cpp 复制代码
// 加载批量同名 Class
struct ClassMultiLoadNode;

UCLASS()
class DATADRIVEN_API UDDWealth : public UObject, public IDDMM
{
	GENERATED_BODY()
	
public:

	// 创建多个同资源名的对象实例
	void BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName ObjectName, FName FunName, TArray<FTransform> SpawnTransforms);

protected:

	// 处理创建多个对象的方法
	void DealClassMultiLoadStack();

protected:

	TArray<ClassMultiLoadNode*> ClassMultiLoadStack;

protected:

	// 批量生成同名 Object 对象的回调函数
	DDOBJFUNC_TWO(BackObjectMulti, FName, BackName, TArray<UObject*>, BackObjects);

	// 批量生成同名 Actor 对象的回调函数
	DDOBJFUNC_TWO(BackActorMulti, FName, BackName, TArray<AActor*>, BackActors);

	// 批量生成同名 Widget 对象的回调函数
	DDOBJFUNC_TWO(BackWidgetMulti, FName, BackName, TArray<UUserWidget*>, BackWidgets);
};

DDWealth.cpp

cpp 复制代码
struct ClassMultiLoadNode
{
	// 加载句柄
	TSharedPtr<FStreamableHandle> WealthHandle;
	// 资源结构体
	FClassWealthEntry* WealthEntry;
	// 请求对象名
	FName ObjectName;
	// 回调方法名
	FName FunName;
	// 生成数量
	int32 Amount;
	// 多个生成位置
	TArray<FTransform> SpawnTransforms;
	// 保存生成的对象与名字
	TArray<UObject*> ObjectGroup;
	TArray<AActor*> ActorGroup;
	TArray<UUserWidget*> WidgetGroup;
	// 构造函数,未加载时使用
	ClassMultiLoadNode(TSharedPtr<FStreamableHandle> InWealthHandle, FClassWealthEntry* InWealthEntry, int32 InAmount, FName InObjectName, FName InFunName, TArray<FTransform> InSpawnTransforms)
	{
		WealthHandle = InWealthHandle;
		WealthEntry = InWealthEntry;
		Amount = InAmount;
		ObjectName = InObjectName;
		FunName = InFunName;
		SpawnTransforms = InSpawnTransforms;
	}
	// 构造函数,已加载时使用
	ClassMultiLoadNode(FClassWealthEntry* InWealthEntry, int32 InAmount, FName InObjectName, FName InFunName, TArray<FTransform> InSpawnTransforms)
	{
		WealthEntry = InWealthEntry;
		Amount = InAmount;
		ObjectName = InObjectName;
		FunName = InFunName;
		SpawnTransforms = InSpawnTransforms;
	}
};

void UDDWealth::WealthTick(float DeltaSeconds)
{


	DealClassMultiLoadStack();	// 加入到 Tick()
}

void UDDWealth::BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName ObjectName, FName FunName, TArray<FTransform> SpawnTransforms)
{
	// 获取对应的资源结构体
	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;
	}
	// 验证 Transform 数组的数量是否为 1 或者为 Amount,或者 Amount = 0
	if ((WealthType == EWealthType::Actor && SpawnTransforms.Num() != 1 && SpawnTransforms.Num() != Amount) || Amount == 0) {
		DDH::Debug() << ObjectName << " Send Error Spawn Count : " << WealthName << DDH::Endl();
		return;
	}
	// 如果已经加载资源
	if (WealthEntry->WealthClass) 
		ClassMultiLoadStack.Push(new ClassMultiLoadNode(WealthEntry, Amount, ObjectName, FunName, SpawnTransforms));
	else {
		// 异步加载
		TSharedPtr<FStreamableHandle> WealthHandle = WealthLoader.RequestAsyncLoad(WealthEntry->WealthPtr.ToSoftObjectPath());
		// 添加新节点
		ClassMultiLoadStack.Push(new ClassMultiLoadNode(WealthHandle, WealthEntry, Amount, ObjectName, FunName, SpawnTransforms));
	}
}

void UDDWealth::DealClassMultiLoadStack()
{
	// 定义完成的节点
	TArray<ClassMultiLoadNode*> CompleteStack;
	for (int i = 0; i < ClassMultiLoadStack.Num(); ++i) {
		// 如果没有加载 UClass, 说明加载句柄有效
		if (!ClassMultiLoadStack[i]->WealthEntry->WealthClass) {
			// 如果加载句柄加载完毕
			if (ClassMultiLoadStack[i]->WealthHandle->HasLoadCompleted())
				ClassMultiLoadStack[i]->WealthEntry->WealthClass = Cast<UClass>(ClassMultiLoadStack[i]->WealthHandle->GetLoadedAsset());
		}
		// 再次判断 WealthClass 是否存在,如果存在进入生成对象阶段
		if (ClassMultiLoadStack[i]->WealthEntry->WealthClass) {
			// 区分类型生成对象
			if (ClassMultiLoadStack[i]->WealthEntry->WealthType == EWealthType::Object) {
				UObject* InstObject = NewObject<UObject>(this, ClassMultiLoadStack[i]->WealthEntry->WealthClass);
				InstObject->AddToRoot();
				ClassMultiLoadStack[i]->ObjectGroup.Push(InstObject);
				// 如果生成完毕
				if (ClassMultiLoadStack[i]->ObjectGroup.Num() == ClassMultiLoadStack[i]->Amount) {
					// 返回对象给请求者
					BackObjectMulti(ModuleIndex, ClassMultiLoadStack[i]->ObjectName, ClassMultiLoadStack[i]->FunName, ClassMultiLoadStack[i]->WealthEntry->WealthName, ClassMultiLoadStack[i]->ObjectGroup);
					// 添加到完成序列
					CompleteStack.Push(ClassMultiLoadStack[i]);
				}
			}
			else if (ClassMultiLoadStack[i]->WealthEntry->WealthType == EWealthType::Actor) {
				// 获取生成位置
				FTransform SpawnTransform = ClassMultiLoadStack[i]->SpawnTransforms.Num() == 1 ? ClassMultiLoadStack[i]->SpawnTransforms[0] : ClassMultiLoadStack[i]->SpawnTransforms[ClassMultiLoadStack[i]->ActorGroup.Num()];
				// 生成对象
				AActor* InstActor = GetDDWorld()->SpawnActor<AActor>(ClassMultiLoadStack[i]->WealthEntry->WealthClass, SpawnTransform);
				// 添加参数数组
				ClassMultiLoadStack[i]->ActorGroup.Push(InstActor);
				// 判断是否生成了全部的对象
				if (ClassMultiLoadStack[i]->ActorGroup.Num() == ClassMultiLoadStack[i]->Amount) {
					// 给请求者传递生成的对象
					BackActorMulti(ModuleIndex, ClassMultiLoadStack[i]->ObjectName, ClassMultiLoadStack[i]->FunName, ClassMultiLoadStack[i]->WealthEntry->WealthName, ClassMultiLoadStack[i]->ActorGroup);
					// 添加到完成序列
					CompleteStack.Push(ClassMultiLoadStack[i]);
				}
			}
			else if (ClassMultiLoadStack[i]->WealthEntry->WealthType == EWealthType::Widget) {
				UUserWidget* InstWidget = CreateWidget<UUserWidget>(GetDDWorld(), ClassMultiLoadStack[i]->WealthEntry->WealthClass);
				// 避免回收
				GCWidgetGroup.Push(InstWidget);
				// 添加参数数组
				ClassMultiLoadStack[i]->WidgetGroup.Push(InstWidget);
				// 判断是否生成了全部的对象
				if (ClassMultiLoadStack[i]->WidgetGroup.Num() == ClassMultiLoadStack[i]->Amount) {
					// 给请求者传递生成的对象
					BackWidgetMulti(ModuleIndex, ClassMultiLoadStack[i]->ObjectName, ClassMultiLoadStack[i]->FunName, ClassMultiLoadStack[i]->WealthEntry->WealthName, ClassMultiLoadStack[i]->WidgetGroup);
					// 添加到完成序列
					CompleteStack.Push(ClassMultiLoadStack[i]);
				}
			}
		}
	}
	// 清空已完成节点
	for (int i = 0; i < CompleteStack.Num(); ++i) {
		ClassMultiLoadStack.Remove(CompleteStack[i]);
		delete CompleteStack[i];
	}
}

补全调用链、测试环节我们留到下一节课。

50. 资源加载系统测试

补全调用链并测试生成多个同名资源对象

补全 DDWealth -- DDModule -- DDOO -- 对象 调用链。

DDModule.h

cpp 复制代码
public:

	// 创建多个同资源名的对象实例
	void BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName ObjectName, FName FunName, TArray<FTransform> SpawnTransforms);

DDModule.cpp

cpp 复制代码
void UDDModule::BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName ObjectName, FName FunName, TArray<FTransform> SpawnTransforms)
{
	Wealth->BuildMultiClassWealth(WealthType, WealthName, Amount, ObjectName, FunName, SpawnTransforms);
}

对于 DDOO 来说,依旧需要根据资源种类来区分不同方法。也不需要传入 ObjectName。

DDOO.h

cpp 复制代码
protected:

	// 创建多个同资源名的对象实例
	void BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName FunName);
	void BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName FunName, FTransform SpawnTransform);
	void BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName FunName, TArray<FTransform> SpawnTransforms);

DDOO.cpp

cpp 复制代码
void IDDOO::BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName FunName)
{
	IModule->BuildMultiClassWealth(WealthType, WealthName, Amount, GetObjectName(), FunName, TArray<FTransform>{ FTransform::Identity });
}

void IDDOO::BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName FunName, FTransform SpawnTransform)
{
	IModule->BuildMultiClassWealth(WealthType, WealthName, Amount, GetObjectName(), FunName, TArray<FTransform>{ SpawnTransform });
}

void IDDOO::BuildMultiClassWealth(EWealthType WealthType, FName WealthName, int32 Amount, FName FunName, TArray<FTransform> SpawnTransforms)
{
	IModule->BuildMultiClassWealth(WealthType, WealthName, Amount, GetObjectName(), FunName, SpawnTransforms);
}

我们打算生成 3 个 ViewActor2 对象,然后让它们在场景里旋转。

WealthCallObject.h

cpp 复制代码
public:

	// 回调方法
	UFUNCTION()
	void BuildActorMulti(FName BackName, TArray<AActor*> BackActors);

WealthCallObject.cpp

cpp 复制代码
void UWealthCallObject::DDLoading()
{
	

	// 测试完毕后记得注释掉
	BuildMultiClassWealth(EWealthType::Actor, "ViewActor2", 3, "BuildActorMulti", SpawnTransforms);
}

void UWealthCallObject::BuildActorMulti(FName BackName, TArray<AActor*> BackActors)
{
	DDH::Debug() << BackName << DDH::Endl();
	KindActors = BackActors;	// 复用 KindActors
}

编译后运行游戏,可以看到左上角输出 ViewActor2,并且 3 个 ViewActor2 对象在场景里旋转。说明创建多个同名 Actor 资源对象的逻辑写好了。

测试生成 Widget 资源对象

前面我们测试都是生成 Actor 类型的资源对象,所以我们还需要测试下 Widget 和 Object 类型的资源对象生成逻辑是否正常。

在 Blueprint 文件夹下新建一个名为 ViewWidget 的文件夹。然后在里面创建 3 个 Widget Blueprint,分别取名为 ViewWidget1 ~ 3

在这 3 个蓝图界面里用 Image 取代原本的 Canvas Panel。并给 3 个 Image 分别赋予 3 张比较明显的笔刷图片(随便选)。

来到 HUDData,给 ClassWealthData 添加 3 个元素如下:

来到 LoadWealthWidget_BP,将原本的 ViewImage 控件缩小一点,然后修改界面如下(注意要给 SizeBox 改名如图所示):

来到 LoadWealthWidget,我们打算利用协程系统来分别运行 3 种生成 Widget 资源对象的方法。

LoadWealthWidget.h

cpp 复制代码
// 提前声明
class USizeBox;

UCLASS()
class RACECARFRAME_API ULoadWealthWidget : public UDDUserWidget
{
	GENERATED_BODY()

public:

	// 生成单个 Widget 的回调函数
	UFUNCTION()
	void BuildSingleWidget(FName BackName, UUserWidget* BackWidget);

	// 生成多个同种类 Widget 的回调函数
	UFUNCTION()
	void BuildKindWidget(TArray<FName> BackNames, TArray<UUserWidget*> BackWidgets);

	// 生成多个同名 Widget 的回调函数
	UFUNCTION()
	void BuildMultiWidget(FName BackName, TArray<UUserWidget*> BackWidgets);

	// 协程方法
	DDCoroTask* BuildWidgetTest();

public:

	// 对应刚刚在 LoadWealthWidget_BP 里添加的 3 个 SizeBox
	UPROPERTY(Meta = (BindWidget))
	USizeBox* SizeBox_1;

	UPROPERTY(Meta = (BindWidget))
	USizeBox* SizeBox_2;

	UPROPERTY(Meta = (BindWidget))
	USizeBox* SizeBox_3;
};

LoadWealthWidget.cpp

cpp 复制代码
// 引入头文件
#include "Components/SizeBox.h"

void ULoadWealthWidget::DDLoading()
{


	// 开启协程,测试完毕后记得注释掉
	StartCoroutine("BuildWidgetTest", BuildWidgetTest());
}

void ULoadWealthWidget::BuildSingleWidget(FName BackName, UUserWidget* BackWidget)
{
	DDH::Debug() << "BuildSingleWidget --> " << BackName << DDH::Endl();

	SizeBox_1->ClearChildren();

	SizeBox_1->AddChild(BackWidget);
}

void ULoadWealthWidget::BuildKindWidget(TArray<FName> BackNames, TArray<UUserWidget*> BackWidgets)
{
	for (int i = 0; i < BackWidgets.Num(); ++i) {
		DDH::Debug() << "BuildKindWidget --> " << BackNames[i] << DDH::Endl();
	}

	SizeBox_1->ClearChildren();
	SizeBox_2->ClearChildren();
	SizeBox_3->ClearChildren();
	
	SizeBox_1->AddChild(BackWidgets[0]);
	SizeBox_2->AddChild(BackWidgets[1]);
	SizeBox_3->AddChild(BackWidgets[2]);
}

void ULoadWealthWidget::BuildMultiWidget(FName BackName, TArray<UUserWidget*> BackWidgets)
{
	DDH::Debug() << "BuildMultiWidget --> " << BackName << DDH::Endl();

	SizeBox_1->ClearChildren();
	SizeBox_2->ClearChildren();
	SizeBox_3->ClearChildren();
	
	SizeBox_1->AddChild(BackWidgets[0]);
	SizeBox_2->AddChild(BackWidgets[1]);
	SizeBox_3->AddChild(BackWidgets[2]);
}

DDCoroTask* ULoadWealthWidget::BuildWidgetTest()
{
	DDCORO_PARAM(ULoadWealthWidget)

#include DDCORO_BEGIN()

	// D 的声明在 DDDefine.h,指向调用协程方法的这个 UserClass 本身
	D->BuildSingleClassWealth(EWealthType::Widget, "ViewWidget2", "BuildSingleWidget");

#include DDYIELD_READY()
	DDYIELD_RETURN_SECOND(10.f);	// 挂起 10 秒

	D->BuildKindClassWealth(EWealthType::Widget, "ViewWidget", "BuildKindWidget");

#include DDYIELD_READY()
	DDYIELD_RETURN_SECOND(10.f);

	D->BuildMultiClassWealth(EWealthType::Widget, "ViewWidget3", 3, "BuildMultiWidget");

#include DDCORO_END()
}

编译后运行游戏,可以看到左上角每隔 10 秒(下面 GIF 图为了缩小图片大小,我调成了间隔 4 秒)就会使用不同的生成方式生成 Widget。一开始是生成单个 Widget 资源对象,后来是生成多个同类种名的 Widget 资源对象,最后是生成多个同名的 Widget 资源对象。

生成多个同种类名的 Widget 资源对象时, ViewWidget2 排在第一是因为他在生成单个 Widget 资源对象时已经加载出来了。

测试生成 Object 资源对象

Object 由于没有实体所以无法直接在场景内显示,我们打算让将其蓝图对象生成出来并注册到框架,通过在蓝图里运行 Print String 蓝图节点来证明它生成成功。

基于 DDObject 创建一个 C++ 类,目标模组为项目,命名为 ViewObject,路径为默认路径。

ViewObject.h

cpp 复制代码
UCLASS(Blueprintable, BlueprintType)	// 可生成蓝图
class RACECARFRAME_API UViewObject : public UDDObject
{
	GENERATED_BODY()
	
public:

	virtual void DDEnable() override;

protected:

	// 实际上用 UFUNCTION + BlueprintImplement 来创建蓝图可运行节点更省资源,此处为了方便,用了反射事件系统
	DDOBJFUNC(EchoSelfInfo);	
	
};

ViewObject.cpp

cpp 复制代码
void UViewObject::DDEnable()
{
	Super::DDEnable();

	// 反射事件自动调用名为 EchoInfo 的方法
	EchoSelfInfo(ModuleIndex, GetObjectName(), "EchoInfo");
}

让 WealthCallObject 来使用协程系统,测试 Object 的三种生成方法。

WealthCallObject.h

cpp 复制代码
public:

	// 生成单个 Object 的回调函数
	UFUNCTION()
	void BuildSingleObject(FName BackName, UObject* BackObject);

	// 生成多个同种类名 Object 的回调函数
	UFUNCTION()
	void BuildKindObject(TArray<FName> BackNames, TArray<UObject*> BackObjects);

	// 生成多个同名 Object 的回调函数
	UFUNCTION()
	void BuildMultiObject(FName BackName, TArray<UObject*> BackObjects);

	// 协程方法
	DDCoroTask* BuildObjectTest();

WealthCallObject.cpp

cpp 复制代码
void UWealthCallObject::DDLoading()
{
	

	// 测试完毕后记得注释掉
	StartCoroutine("BuildObjectTest", BuildObjectTest());
}

void UWealthCallObject::BuildSingleObject(FName BackName, UObject* BackObject)
{
	DDH::Debug() << "BuildSingleObject --> " << BackName << DDH::Endl();

	IDDOO* InstPtr = Cast<IDDOO>(BackObject);
	if (InstPtr)
		InstPtr->RegisterToModule(ModuleIndex);
}

void UWealthCallObject::BuildKindObject(TArray<FName> BackNames, TArray<UObject*> BackObjects)
{
	for (int i = 0; i < BackObjects.Num(); ++i) {
		DDH::Debug() << "BuildKindObject --> " << BackNames[i] << DDH::Endl();
	
		IDDOO* InstPtr = Cast<IDDOO>(BackObjects[i]);
		if (InstPtr)
			InstPtr->RegisterToModule(ModuleIndex);
	}
}

void UWealthCallObject::BuildMultiObject(FName BackName, TArray<UObject*> BackObjects)
{
	DDH::Debug() << "BuildMultiObject --> " << BackName << DDH::Endl();

	for (int i = 0; i < BackObjects.Num(); ++i) {
		IDDOO* InstPtr = Cast<IDDOO>(BackObjects[i]);
		if (InstPtr)
			InstPtr->RegisterToModule(ModuleIndex);
	}
}

DDCoroTask* UWealthCallObject::BuildObjectTest()
{
	DDCORO_PARAM(UWealthCallObject)

#include DDCORO_BEGIN()

	D->BuildSingleClassWealth(EWealthType::Object, "ViewObject2", "BuildSingleObject");

#include DDYIELD_READY()
	DDYIELD_RETURN_SECOND(10.f);

	D->BuildKindClassWealth(EWealthType::Object, "ViewObject", "BuildKindObject");

#include DDYIELD_READY()
	DDYIELD_RETURN_SECOND(10.f);

	D->BuildMultiClassWealth(EWealthType::Object, "ViewObject3", 3, "BuildMultiObject");

#include DDCORO_END()
}

编译后,在 Blueprint 下创建一个名为 ViewObject 的文件夹。在里面基于 ViewObject 创建 3 个蓝图,分别命名为 ViewObject1 ~ 3

在这 3 个蓝图里面都创建一个名为 EchoInfo 的函数,往里面添加 Pring String 的节点。

打开 PlayerData,给 ClassWealthData 添加 3 个元素如下:

运行游戏,可以看到每隔 10 秒左上角就输出了不同生成 Object 资源对象方式的 Debug 语句。初始是生成单个 Object 资源对象,随后是生成 3 个同种类名的 Object 资源对象,最后是生成 3 个同名 Object 资源对象。

至此,整个资源加载系统的编写以及测试都完成了。

相关推荐
ö Constancy1 小时前
c++ 笔记
开发语言·c++
fengbizhe1 小时前
笔试-笔记2
c++·笔记
余为民同志1 小时前
mini-lsm通关笔记Week2Day4
笔记
墨染风华不染尘1 小时前
python之开发笔记
开发语言·笔记·python
徐霞客3201 小时前
Qt入门1——认识Qt的几个常用头文件和常用函数
开发语言·c++·笔记·qt
fpcc1 小时前
redis6.0之后的多线程版本的问题
c++·redis
螺旋天光极锐斩空闪壹式!2 小时前
自制游戏:监狱逃亡
c++·游戏
澜世2 小时前
2024小迪安全基础入门第三课
网络·笔记·安全·网络安全
Bald Baby2 小时前
JWT的使用
java·笔记·学习·servlet
工业3D_大熊2 小时前
3D可视化引擎HOOPS Luminate场景图详解:形状的创建、销毁与管理
java·c++·3d·docker·c#·制造·数据可视化