在游戏开发中,Json 文件常被用来保存游戏数据或配置参数,如把游戏对象的内部状态存储到磁盘文件,即序列化游戏对象的时候,或在文件中配置一些游戏相关的参数时。本文将详细讲解如何在 UE 中读取与解析 Json 文件。
创建一个 JSONFileReadWrite 类,两个成员函数 ReadJSONFileByFN、WriteJSONFile。功能分别是读取一个 JSON 格式的文件,并可以解析其中数据;另一个功能是写入一个 JSON 文件。
{
"Game": "LOL",
"Year": 2023,
"Judge":
{
"name": "Uzi",
"age": 26,
},
"Player": [
{
"name": "xiaoming",
"levels": 22
},
{
"name": "xiaohu",
"levels": 23
}
]
}
普通类型的值:Json数据格式就是一种嵌套的关系,花括号里面其实就是保存了一个个键值对(学过C++map容器应该很好理解)例如,Game和Year就是Key键,“LOL”、2023就是对应的值,只不过一个是字符串类型,一个是整数类型。
"Game": "LOL",
"Year": 2023,
Json对象类型的值:当然也可以是一个Json对象类型,如下Judge的值就是一个花括号包裹住的类型,也就是一个Json对象。
"Judge":
{
"name": "Uzi",
"age": 26,
},
数组类型的值:如下所示,Player的值是由 [ ] 包围住,其中数组是Json对象类型
"Player": [
{
"name": "xiaoming",
"levels": 22
},
{
"name": "xiaohu",
"levels": 23
}
]
在了解Json数据的基本格式后,就可以对其进行读写操作。
创建一个UE C++工程,并新建一个JSONFileReadWrite类继承UObject类,创建两个函数,并且让这个C++类和成员函数可以被蓝图调用(加入说明符即可)。
// 类是使用BlueprintType将其暴露给蓝图使用
UCLASS(BlueprintType)
class CPP_API UJSONFileReadWrite : public UObject
{
GENERATED_BODY()
public:
// 函数是使用BlueprintCallable将其暴露给蓝图使用
UFUNCTION(BlueprintCallable)
void ReadJSONFileByFN();
UFUNCTION(BlueprintCallable)
void WriteJSONFile();
};
使用UE的Json功能时,需要在build.cs文件中添加Json模块依赖,不然编译不通过。
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Json" });
大致思路
【提示】使用文件选择对话框需要下面两个头文件
#include "Developer/DesktopPlatform/Public/IDesktopPlatform.h"
#include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h"
#include "Developer/DesktopPlatform/Public/IDesktopPlatform.h"
#include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h"
void UJSONFileReadWrite::ReadJSONFileByFN()
{
//-----------------------------------------------------------------------------------------------------------------
//1.1 选择磁盘中的Json文件,并获取Json文件绝对路径
TArray<FString> JsonFilePaths; //保存文件的绝对路径
FString ExtensionStr = TEXT("*.*"); //文件类型
const FString ProjectDirPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir()); //获取工程目录的绝对路径
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
DesktopPlatform->OpenFileDialog(nullptr, TEXT("文件"), FPaths::ConvertRelativePathToFull(FPaths::ProjectDir()), TEXT(""), *ExtensionStr, EFileDialogFlags::None, JsonFilePaths);
//判断文件是否存在
if ( !FPlatformFileManager::Get().GetPlatformFile().FileExists(*JsonFilePaths[0]) )
{
UE_LOG( LogTemp, Warning, TEXT("%s not exist"), *JsonFilePaths[0] );
return;
}
//1.2 根据文件路径读取文件内存,保存到FString变量中
FString JsonStr;
FFileHelper::LoadFileToString(JsonStr, *(JsonFilePaths[0]));
//-----------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------
//2.将 JsonStr 变量存储到一个 FJsonObject 变量中
TSharedRef<TJsonReader<>> JsonReader = TJsonReaderFactory<TCHAR>::Create(JsonStr); //创建一个Json 阅读器
TSharedPtr<FJsonObject> JsonObject; //创建一个Json对象
FJsonSerializer::Deserialize(JsonReader, JsonObject); //反序列化,将JsonReader里面的数据,传到JsonObject中
//-----------------------------------------------------------------------------------------------------------------
//3.读取Json对象中的数据(例如,读取Game对应的数据值)
FString sGameValue = JsonObject->GetStringField("Game");
UE_LOG(LogTemp, Warning, TEXT("Game Value: %s"), *sGameValue);
return;
}
蓝图中验证功能
在关卡蓝图中写如下代码日志文件输出结果如图:结果正确打印出来。
大致思路
// 存放数据的结构体
struct Info {
FString name;
int32 health;
};
void UJSONFileReadWrite::WriteJSONFile()
{
//-----------------------------------------------------------------------------------------------------------------
//1. 准备阶段
//1.1 声明存储写入的Json内容的字符串
FString JsonStr;
//1.2创建一个Json编写器
TSharedRef<TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>> JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(&JsonStr);
//-----------------------------------------------------------------------------------------------------------------
//2. 写入单个数据
JsonWriter->WriteObjectStart(); //开始 一个Json对象的写入(一个Json对象对应一个{}中的内容)
JsonWriter->WriteValue(TEXT("Time"), TEXT("1998")); //写入 一个键值对("Time" : "1998")
JsonWriter->WriteValue(TEXT("age"), TEXT("27")); //写入 一个键值对("age" : "27")
JsonWriter->WriteObjectEnd(); //结束 一个Json对象的写入
//2.1 写入数组数据
TArray<Info> Players; //存放数组数据的变量
struct Info info;
info.name = TEXT("player1"); info.health = 30; Players.Add(info);
info.name = TEXT("player2"); info.health = 200; Players.Add(info);
info.name = TEXT("player3"); info.health = 999; Players.Add(info);
//JsonWriter->WriteArrayStart(L"players"); ???为什么调用WriteArrayStart函数带参数就会报错:数组越界
JsonWriter->WriteArrayStart();
for (Info player : Players)
{
JsonWriter->WriteObjectStart();
JsonWriter->WriteValue(L"name", player.name);
JsonWriter->WriteValue(L"health", player.health);
JsonWriter->WriteObjectEnd();
}
JsonWriter->WriteArrayEnd();
//-----------------------------------------------------------------------------------------------------------------
//3. 停止写入操作
JsonWriter->Close();
//4. 打印结果
UE_LOG(LogTemp, Warning, TEXT("JsonStr Value: %s"), *JsonStr);
return;
}
LOG输出结果:
为什么调用WriteArrayStart函数时带参数就会报错:数组越界。我看别的博主都是带参数调用都没有问题。异常内容如下,望各位大佬指点。