UE DataTable - 数据表

一、DataTable 是什么

        DataTable 就是数据表,也就是一个二维的 M 行 N 列的矩阵,如下图所示就是一个七行六列的数据表:

程序可以通过策划配置的数据表找到对应关系做相应的逻辑,对策划很友好。


二、在编辑器中使用

1.创建一个结构体

        首先创建一个结构体,该结构体就是我们要创建的数据表的列数据,然后再在新创建的结构体中添加变量,可以在Default Values页面设置添加数据时的默认值:

2. 创建一个数据表

        在编辑器中右键,Miscellaneous -> DataTable 即可创建一个 DataTable:

         创建数据表的时候,需要选择一个结构体,选择我们刚才新创建的那个结构体即可,这样创建出来的数据表的列就是刚才结构体中的变量:

         新创建的数据表默认是空的, 点击 Add 按钮可以添加一个默认行,第一列的Row Name是自动生成的。Row Name 用来唯一标识每一行,相当于数据库中的主键,可以修改,但不能有相同的值。添加完成后,点击数据表中的一行,这一行会高亮,且可以在 Row Editor 中修改这一行的值。

3. 蓝图中获取数据表中数据

        可以使用节点GetDataTableRowNames获取数据表中全部行的Row Name:

        使用节点GetDataTableRow根据Row Name获取该Row Name那一行的数据:

         可以这样读取数据表中的数据打印出来:

4. 导入CSV为数据表

         在编辑器中右键,导入资源到文件夹,然后选择要导入的CSV文件:

         导入的时候也需要选择该数据表所使用的结构体。


三、代码中使用

1. 使用代码创建一个列结构

        继承FTableRowBase类,需要包含头文件"Engine/DataTable.h",同时由于添加结构体用到USTRUCT,加入了反射系统,还需要包含该文件的.generated.h头文件:

USTRUCT(BlueprintType)
struct FTableRowTest : public FTableRowBase
{
	GENERATED_USTRUCT_BODY()

public:
	FTableRowTest(){}

	FTableRowTest(FString InName, int32 InCurrentCount, int32 InMaxNum, float InLifeTime)
		:name(InName)
		, CurrentCount(InCurrentCount)
		, MaxNum(InMaxNum)
		, LifeTime(InLifeTime)
	{
		
	}

	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "名字")
	FString name;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "当前数量")
	int64 CurrentCount = 0;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "最大数量")
	int64 MaxNum = 100;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "生命周期")
	float LifeTime = 10.0f;
};

         编译过后就可以在创建数据表的时候看到刚才创建的结构体选项了:

2. 通过代码读数据表

        可以通过FindRow读取某一行的数据:

UDataTable* const UserInfoDataTable = LoadObject<UDataTable>(this, TEXT("DataTable'/Game/CPPFunction/DataDrive/DT_UserInfo.DT_UserInfo'"));
if (UserInfoDataTable)
{
	for (FName RowName : UserInfoDataTable->GetRowNames())
	{
		FTableRowTest* TestInfo = UserInfoDataTable->FindRow<FTableRowTest>(RowName, TEXT("name"));
		if (TestInfo)
		{
			UKismetSystemLibrary::PrintString(GetWorld(), TestInfo->name);
		}
	}
}
else
{
	UKismetSystemLibrary::PrintString(GetWorld(), TEXT(" Not Find DataTable!"));
}

         可以通过GetRowMap读取数据表中全部数据:

UDataTable* const UserInfoDataTable = LoadObject<UDataTable>(this, TEXT("DataTable'/Game/CPPFunction/DataDrive/DT_UserInfo.DT_UserInfo'"));
if (UserInfoDataTable)
{
	for (auto it : UserInfoDataTable->GetRowMap())
	{
		FString RowName = (it.Key).ToString();

		FTableRowTest* TestInfo = (FTableRowTest*)it.Value;

		UKismetSystemLibrary::PrintString(GetWorld(), FString::Printf(TEXT("%s %s"), *RowName, *TestInfo->name));
	}
}

3. 通过代码写数据表

        在代码中可以直接通过资源路径和名称加载数据表,比如在 Content/TestForDT 目录下的 “MyTestDT”,可以这样加载:

UDataTable* const TestTable = LoadObject<UDataTable>(nullptr, TEXT("/Game/TestForDT/MyTestDT.MyTestDT"));

         然后就可以通过 void UDataTable::AddRow(FName RowName, const FTableRowBase& RowData) 来新增行了。比如:

UDataTable* const UserInfoDataTable = LoadObject<UDataTable>(this, TEXT("DataTable'/Game/CPPFunction/DataDrive/DT_UserInfo.DT_UserInfo'"));
if (UserInfoDataTable)
{
	FSimpleStruct* UserInfo = new FSimpleStruct();
	UserInfo->name = TEXT("Lily");
	UserInfo->health = 80;
	FName RowName = TEXT("Player3");
	UserInfoDataTable->AddRow(RowName, *UserInfo);
}

4. 导入CSV

  • csv 文件
---,name,health,icon
Player4,"小明","200","Texture2D'/Game/FourEvilDragonsHP/Textures/DragonTheUsurper/BlueHPTex.BlueHPTex'"
Player5,"小红","90","Texture2D'/Game/FourEvilDragonsHP/Textures/DragonTheSoulEater/BlueHPTex.BlueHPTex'"
Player6,"小张","150","None"
  • 填充现有的 DataTable 
UDataTable* const UserInfoDataTable = LoadObject<UDataTable>(this, TEXT("DataTable'/Game/CPPFunction/DataDrive/DT_UserInfo.DT_UserInfo'"));
if (UserInfoDataTable)
{
	FString CSVPath = FPaths::ProjectDir() + TEXT("DataDrive/UserInfo.csv");
	CSVPath = FPaths::ConvertRelativePathToFull(CSVPath);
	if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*CSVPath))
	{
		UDataTableFunctionLibrary::FillDataTableFromCSVFile(UserInfoDataTable, CSVPath);
	}
}
  • 生成 UDataTable
UDataTable* const UDataTable* ADataDriveActor::CreateDataTableFromCSV()
{
	FString CSVPath = FPaths::ProjectDir() + TEXT("DataDrive/UserInfo.csv");
	CSVPath = FPaths::ConvertRelativePathToFull(CSVPath);
	if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*CSVPath))
	{
		UKismetSystemLibrary::PrintString(GetWorld(), *CSVPath);
		FString CSVData;
		FFileHelper::LoadFileToString(CSVData, *CSVPath);
		UDataTable* DT_UserInfo = NewObject<UDataTable>(GetTransientPackage(), FName(TEXT("DT_UserInfo2")));
		DT_UserInfo->RowStruct = FSimpleStruct::StaticStruct();
		DT_UserInfo->CreateTableFromCSVString(CSVData);

		return DT_UserInfo;
	}
	return nullptr;
}

 5. 导出 CSV

        使用GetTableAsCSV():

UDataTable* const UserInfoDataTable = LoadObject<UDataTable>(this, TEXT("DataTable'/Game/CPPFunction/DataDrive/DT_UserInfo.DT_UserInfo'"));
if (UserInfoDataTable)
{
	FString CSVString = UserInfoDataTable->GetTableAsCSV();
	FString CSVPath = FPaths::ProjectDir() + TEXT("DataDrive/UserInfo2.csv");
	FFileHelper::SaveStringToFile(CSVString, *CSVPath, FFileHelper::EEncodingOptions::ForceUTF8);
}

猜你喜欢

转载自blog.csdn.net/Sakuya__/article/details/123797240
今日推荐