一、DataTable 是什么
????????DataTable 就是数据表,也就是一个二维的 M 行 N 列的矩阵,如下图所示就是一个七行六列的数据表:
程序可以通过策划配置的数据表找到对应关系做相应的逻辑,对策划很友好。
二、在编辑器中使用
1.创建一个结构体
? ? ? ? 首先创建一个结构体,该结构体就是我们要创建的数据表的列数据,然后再在新创建的结构体中添加变量,可以在Default Values页面设置添加数据时的默认值:
2. 创建一个数据表
????????在编辑器中右键,Miscellaneous -> DataTable 即可创建一个 DataTable:
? ? ? ? ?创建数据表的时候,需要选择一个结构体,选择我们刚才新创建的那个结构体即可,这样创建出来的数据表的列就是刚才结构体中的变量:
? ? ? ? ?新创建的数据表默认是空的, 点击 Add 按钮可以添加一个默认行,第一列的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
---,name,health,icon
Player4,"马克","200","Texture2D'/Game/FourEvilDragonsHP/Textures/DragonTheUsurper/BlueHPTex.BlueHPTex'"
Player5,"冉冰","90","Texture2D'/Game/FourEvilDragonsHP/Textures/DragonTheSoulEater/BlueHPTex.BlueHPTex'"
Player6,"墨城","150","None"
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* 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);
}
|