当前位置:   article > 正文

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

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

49. 创建多个资源对象

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

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

DDModule.h

public:

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

DDModule.cpp

void UDDModule::BuildKindClassWealth(EWealthType WealthType, FName WealthKind, FName ObjectName, FName FunName, TArray<FTransform> SpawnTransforms)
{
	Wealth->BuildKindClassWealth(WealthType, WealthKind, ObjectName, FunName, SpawnTransforms);
}
  • 1
  • 2
  • 3
  • 4

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

DDOO.h

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

DDOO.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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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

WealthCallObject.h

public:

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

public:

	// 存储生成的 Actor
	TArray<AActor*> KindActors;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

WealthCallObject.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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

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

在这里插入图片描述

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

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

DDWealth.h

// 加载批量同名 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);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

DDWealth.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];
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144

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

50. 资源加载系统测试

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

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

DDModule.h

public:

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

DDModule.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);
}
  • 1
  • 2
  • 3
  • 4

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

DDOO.h

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

DDOO.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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

WealthCallObject.h

public:

	// 回调方法
	UFUNCTION()
	void BuildActorMulti(FName BackName, TArray<AActor*> BackActors);
  • 1
  • 2
  • 3
  • 4
  • 5

WealthCallObject.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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

编译后运行游戏,可以看到左上角输出 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

// 提前声明
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;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

LoadWealthWidget.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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

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

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

在这里插入图片描述

测试生成 Object 资源对象

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

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

ViewObject.h

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

	virtual void DDEnable() override;

protected:

	// 实际上用 UFUNCTION + BlueprintImplement 来创建蓝图可运行节点更省资源,此处为了方便,用了反射事件系统
	DDOBJFUNC(EchoSelfInfo);	
	
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

ViewObject.cpp

void UViewObject::DDEnable()
{
	Super::DDEnable();

	// 反射事件自动调用名为 EchoInfo 的方法
	EchoSelfInfo(ModuleIndex, GetObjectName(), "EchoInfo");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

WealthCallObject.h

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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

WealthCallObject.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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

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

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

在这里插入图片描述
打开 PlayerData,给 ClassWealthData 添加 3 个元素如下:
在这里插入图片描述

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

在这里插入图片描述
至此,整个资源加载系统的编写以及测试都完成了。

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

闽ICP备14008679号