UE4 从无到有纯 C++ & Slate 开发沙盒游戏(十一) 读取存档Json文件
上一篇只是将一个Json文件加载进内存,并没有对文件进行解析,接下来写一个解析Json文件的方法,把文件的中的字符串解析成我们所需要的数据资源
首先将SlAiSingleton.cpp中的内容都放置到 SlAiSingleton.h 中
d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Public\Data\SlAiSingleton.h
1 #include "CoreMinimal.h" 2 3 /** 4 * 5 */ 6 template<class T> 7 class SLAICOURSE_API SlAiSingleton 8 { 9 public: 10 static TSharedPtr<T> Get(); 11 12 private: 13 14 static void Initialize(); 15 16 static TSharedRef<T> Create(); 17 18 private: 19 static TSharedPtr<T> TInstance; 20 21 }; 22 23 24 template<class T> 25 TSharedPtr<T> SlAiSingleton<T>::TInstance = NULL; 26 27 //创建一个共享的引用 28 template<class T> 29 TSharedRef<T> SlAiSingleton<T>::Create() 30 { 31 TSharedRef<T> TRef = MakeShareable(new T()); 32 return TRef; 33 } 34 35 template<class T> 36 void SlAiSingleton<T>::Initialize() 37 { 38 //判断指针是否存在,如果不存在则Cteate一个 39 if (!TInstance.IsValid()) 40 { 41 TInstance = Create(); 42 } 43 } 44 45 template<class T> 46 TSharedPtr<T> SlAiSingleton<T>::Get() 47 { 48 Initialize(); 49 return TInstance; 50 }
d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Private\Data\SlAiSingleton.cpp
SlAiSingleton.cpp 文件中则没有内容
1 #include "Data/SlAiSingleton.h"
解析Json文件相关内容
D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Public\Data\SlAiJsonHandle.h
1 #include "CoreMinimal.h" 2 #include "SlAiTypes.h" 3 #include "Json.h" 4 5 6 /** 7 * 8 */ 9 class SLAICOURSE_API SlAiJsonHandle 10 { 11 public: 12 SlAiJsonHandle(); 13 14 /** 15 * 解析存档的方法 16 *Culture 为 ECultureTeam 下的 EN、ZH等值, 17 * 四个参数分别对应Json中的 Culture、MusicVolume、SoundVolume、RecordData 18 */ 19 void RecordDataJsonRead(FString& Culture, float& MusicVolume, float& SoundVolume, TArray<FString>& RecordDataList); 20 21 private: 22 //读取Json文件到字符串 23 bool LoadStringFromFile(const FString& FileName, const FString& RelaPath, FString& ResultString); 24 25 private: 26 //存档文件名 27 FString RecordDataFileName; 28 //相对路径 29 FString RelativePath; 30 31 };
D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\Data\SlAiJsonHandle.cpp
1 #include "Data/SlAiJsonHandle.h" 2 #include "Common/SlAiHelper.h" 3 4 SlAiJsonHandle::SlAiJsonHandle() 5 { 6 RecordDataFileName = FString("RecordData.json"); 7 RelativePath = FString("Res/ConfigData/"); 8 } 9 10 void SlAiJsonHandle::RecordDataJsonRead(FString& Culture, float& MusicVolume, float& SoundVolume, TArray<FString>& RecordDataList) 11 { 12 //保存读取到的所有 Json 数据 13 FString JsonValue; 14 15 //读取文件保存到 JsonValue 16 LoadStringFromFile(RecordDataFileName, RelativePath, JsonValue); 17 18 //这是一个二维数组,用来保存解析出来的数据 19 TArray<TSharedPtr<FJsonValue>> JsonParsed; 20 21 //将读取出来的数据通过一个Json读取的共享类TJsonReaderFactory 保存到JsonReader的引用 22 TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(JsonValue); 23 24 //解析 25 if (FJsonSerializer::Deserialize(JsonReader, JsonParsed)) 26 { 27 //从对应数组下标,获取对应类型,对应字段的数据 28 Culture = JsonParsed[0]->AsObject()->GetStringField(FString("Culture")); 29 MusicVolume = JsonParsed[1]->AsObject()->GetNumberField(FString("MusicVolume")); 30 SoundVolume = JsonParsed[2]->AsObject()->GetNumberField(FString("SoundVolume")); 31 32 //获取存档数据 33 TArray<TSharedPtr<FJsonValue>> RecordDataArray = JsonParsed[3]->AsObject()->GetArrayField(FString("RecordData")); 34 for (int i = 0; i < RecordDataArray.Num(); ++i) 35 { 36 FString RecordDataName = RecordDataArray[i]->AsObject()->GetStringField(FString::FromInt(i)); 37 //保存到 38 RecordDataList.Add(RecordDataName); 39 } 40 } 41 else 42 { 43 SlAiHelper::Debug(FString("Deserialize Failed")); 44 } 45 } 46 47 bool SlAiJsonHandle::LoadStringFromFile(const FString& FileName, const FString& RelaPath, FString& ResultString) 48 { 49 if (!FileName.IsEmpty()) 50 { 51 //获取绝对路径 (ProjectContentDir() 是原来的 GameContentDir(), 4.26版本后改名了) 52 FString AbsoPath = FPaths::ProjectContentDir() + RelaPath + FileName; 53 54 //判断文件是否存在 55 if (FPaths::FileExists(AbsoPath)) 56 { 57 if (FFileHelper::LoadFileToString(ResultString, *AbsoPath)) 58 { 59 return true; 60 } 61 else 62 { 63 //加载不成功 64 SlAiHelper::Debug(FString("Load Error!!") + AbsoPath); 65 return false; 66 } 67 } 68 else 69 { 70 //输出文件不存在 71 SlAiHelper::Debug(FString("File Not Exist!!") + AbsoPath); 72 } 73 } 74 return false; 75 }
然后菜单初始化是调用Json文件,将配置内容初始化
d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Public\Data\SlAiDataHandle.h
1 #include "SlAiTypes.h" 2 #include "CoreMinimal.h" 3 4 5 class SLAICOURSE_API SlAiDataHandle 6 { 7 public: 8 SlAiDataHandle(); 9 10 static void Initialize(); 11 12 static TSharedPtr<SlAiDataHandle> Get(); 13 14 //修改语言 15 void ChangeLocalizationCulture(ECultureTeam Culture); 16 //修改菜单音量大小 17 void ResetMenuVolume(float MusicVol, float SoundVol); 18 19 public: 20 /** 21 * 这里没有使用 GamePlay 框架的 GameInstance,变量直接写到C++类中除非你主动销毁,否则他会一直存在 22 */ 23 //语言状态 24 ECultureTeam CurrentCulture; 25 //音乐状态 26 float MusicVolume; 27 //音效状态 28 float SoundVolume; 29 //存档数据 30 TArray<FString> RecordDataList; 31 32 private: 33 //创建单例 34 static TSharedRef<SlAiDataHandle> Create(); 35 36 //根据enum类型获取字符串(该方法只能用于UENUM()反射后的枚举,普通枚举不能这样搞) 37 template<typename TEnum> 38 FString GetEnumValueAsString(const FString& Name, TEnum Value); 39 40 //根据字符串获取enum值(该方法只能用于UENUM()反射后的枚举,普通枚举不能这样搞) 41 template<typename TEnum> 42 TEnum GetEnumValueFromString(const FString& Name, FString Value); 43 44 //初始化存档数据 45 void InitRecordData(); 46 47 private: 48 static TSharedPtr<SlAiDataHandle> DataInstance; 49 };
D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\Data\SlAiDataHandle.cpp
1 #include "Data/SlAiDataHandle.h" 2 #include "Internationalization/Internationalization.h" 3 #include "Data/SlAiSingleton.h" 4 #include "Data/SlAiJsonHandle.h" 5 #include "Common/SlAiHelper.h" 6 7 TSharedPtr<SlAiDataHandle> SlAiDataHandle::DataInstance = NULL; 8 9 SlAiDataHandle::SlAiDataHandle() 10 { 11 ////初始化中文 12 //CurrentCulture = ECultureTeam::ZH; 13 ////初始化音乐 14 //MusicVolume = 0.5f; 15 ////初始化音效 16 //SoundVolume = 0.5f; 17 18 //初始化存档数据 19 InitRecordData(); 20 } 21 22 void SlAiDataHandle::Initialize() 23 { 24 if (!DataInstance.IsValid()) 25 { 26 DataInstance = Create(); 27 } 28 } 29 30 TSharedPtr<SlAiDataHandle> SlAiDataHandle::Get() 31 { 32 Initialize(); 33 return DataInstance; 34 } 35 36 TSharedRef<SlAiDataHandle> SlAiDataHandle::Create() 37 { 38 /** 39 *MakeShareable 可以用来创建共享指针和共享引用 40 */ 41 TSharedRef<SlAiDataHandle> DataRef = MakeShareable(new SlAiDataHandle()); 42 return DataRef; 43 } 44 45 void SlAiDataHandle::ChangeLocalizationCulture(ECultureTeam Culture) 46 { 47 switch (Culture) 48 { 49 case ECultureTeam::EN: 50 FInternationalization::Get().SetCurrentCulture(TEXT("en")); 51 break; 52 case ECultureTeam::ZH: 53 FInternationalization::Get().SetCurrentCulture(TEXT("zh")); 54 break; 55 } 56 //赋值 57 CurrentCulture = Culture; 58 } 59 60 void SlAiDataHandle::ResetMenuVolume(float MusicVol, float SoundVol) 61 { 62 if (MusicVol > 0) 63 { 64 MusicVolume = MusicVol; 65 } 66 if (SoundVol > 0) 67 { 68 SoundVolume = SoundVol; 69 } 70 } 71 72 //根据枚举值返回字符串 73 template<typename TEnum> 74 FString SlAiDataHandle::GetEnumValueAsString(const FString& Name, TEnum Value) 75 { 76 //通过UE4的FindObject寻找所有ANY_PACKAGE反射到的Name,寻找到后实例化后返回 77 const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, *Name, ture); 78 79 if (!EnumPtr) 80 { 81 return FString("InValid"); 82 } 83 return EnumPtr->GetEnumName((int32)Value); 84 } 85 86 //根据字符串返回枚举值 87 template<typename TEnum> 88 TEnum SlAiDataHandle::GetEnumValueFromString(const FString& Name, FString Value) 89 { 90 const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, *Name, true); 91 92 if (!EnumPtr) 93 { 94 return TEnum(0); 95 } 96 return (TEnum)EnumPtr->GetIndexByName(FName(*FString(Value))); 97 } 98 99 void SlAiDataHandle::InitRecordData() 100 { 101 //获取语言 102 FString Culture; 103 //使用单例读取存档数据 104 SlAiSingleton<SlAiJsonHandle>::Get()->RecordDataJsonRead(Culture, MusicVolume, SoundVolume, RecordDataList); 105 106 //初始化语言 107 ChangeLocalizationCulture(GetEnumValueFromString<ECultureTeam>(FString("ECultureTeam"), Culture)); 108 109 //输出打印 110 SlAiHelper::Debug(Culture + FString("--") + FString::SanitizeFloat(MusicVolume) + FString("--") + FString::SanitizeFloat(SoundVolume), 20.f); 111 112 //输出打印 RecordDataList 使用迭代器循环读取RecordDataList 113 for (TArray<FString>::TIterator It(RecordDataList); It; It++) 114 { 115 SlAiHelper::Debug(*It, 20.f); 116 } 117 }
====================================================================================================================================