Fork me on GitHub

UE4 从无到有纯 C++ & Slate 开发沙盒游戏(十二) 写入存档Json文件

上一部分写的是Json文件的读取,并将读取到的内容初始化到设置界面对应的配置项上,而游戏中改变设置配置则无法保存到Json文件中,这一部分将会实现Json文件的配置写入。

 首先要先实现两个方法

1. 将JSon转换为Json格式字符串的方法

2. 保存字符串到文件的方法

 

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     //FJsonObject转换为Json格式的字符串
26     bool GetFStringInJSonData(const TSharedPtr<FJsonObject>& JsonObj, FString& JsonStr);
27 
28     //保存字符串到文件
29     bool WriteFileWithJsonData(const FString& JsonStr, const FString& RelaPath, const FString& FileName);
30 
31 private:
32     //存档文件名
33     FString RecordDataFileName;
34     //相对路径
35     FString RelativePath;
36 
37 };

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 }
 76 
 77 bool SlAiJsonHandle::GetFStringInJSonData(const TSharedPtr<FJsonObject>& JsonObj, FString& JsonStr)
 78 {
 79     if (JsonObj.IsValid() && JsonObj->Values.Num() > 0)
 80     {
 81         TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<TCHAR>::Create(&JsonStr);
 82         FJsonSerializer::Serialize(JsonObj.ToSharedRef(), JsonWriter);
 83         return true;
 84     }
 85     return false;
 86 }
 87 
 88 bool SlAiJsonHandle::WriteFileWithJsonData(const FString& JsonStr, const FString& RelaPath, const FString& FileName)
 89 {
 90     if (!JsonStr.IsEmpty())    //判断字符串是否为空
 91     {
 92         if (!FileName.IsEmpty())
 93         {
 94             FString AbsoPath = FPaths::ProjectContentDir() + RelaPath + FileName;
 95             //保存
 96             if (FFileHelper::SaveStringToFile(JsonStr, *AbsoPath))
 97             {
 98                 return true;
 99             }
100             else
101             {
102                 SlAiHelper::Debug(FString("Save") + AbsoPath + FString("-->Failed"), 30.f);
103             }
104         }
105         SlAiHelper::Debug(FString("!FileName.IsEmpty() ==False"), 30.f);
106     }
107     SlAiHelper::Debug(FString("!JsonStr.IsEmpty() ==False"), 30.f);
108 }

 

然后开始写更新数据,需要在 SlAiDataHandle 中调用 SlAiJsonHandle 的方法

先转换成JsonObject,然后转成Json,然后存入到存档文件

再在 SlAiDataHandle 文件中添加一个修改存档的 public 方法 UpdateRecordData,这个方法没写返回值,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     //修改存档
22     void UpdateRecordData(FString Culture, float MusicVolume, float SoundVolume, TArray<FString>* RecordDataList);
23 
24 private:
25     //读取Json文件到字符串
26     bool LoadStringFromFile(const FString& FileName, const FString& RelaPath, FString& ResultString);
27 
28     //FJsonObject转换为Json格式的字符串
29     bool GetFStringInJSonData(const TSharedPtr<FJsonObject>& JsonObj, FString& JsonStr);
30 
31     //保存字符串到文件
32     bool WriteFileWithJsonData(const FString& JsonStr, const FString& RelaPath, const FString& FileName);
33 
34 private:
35     //存档文件名
36     FString RecordDataFileName;
37     //相对路径
38     FString RelativePath;
39 
40 };

 

UpdateRecordData 实现

D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\Data\SlAiJsonHandle.cpp

  1 // Fill out your copyright notice in the Description page of Project Settings.
  2 
  3 #include "Data/SlAiJsonHandle.h"
  4 #include "Common/SlAiHelper.h"
  5 
  6 SlAiJsonHandle::SlAiJsonHandle()
  7 {
  8     RecordDataFileName = FString("RecordData.json");
  9     RelativePath = FString("Res/ConfigData/");
 10 }
 11 
 12 void SlAiJsonHandle::RecordDataJsonRead(FString& Culture, float& MusicVolume, float& SoundVolume, TArray<FString>& RecordDataList)
 13 {
 14     //保存读取到的所有 Json 数据
 15     FString JsonValue;
 16 
 17     //读取文件保存到 JsonValue
 18     LoadStringFromFile(RecordDataFileName, RelativePath, JsonValue);
 19 
 20     //这是一个二维数组,用来保存解析出来的数据
 21     TArray<TSharedPtr<FJsonValue>> JsonParsed;
 22 
 23     //将读取出来的数据通过一个Json读取的共享类TJsonReaderFactory 保存到JsonReader的引用
 24     TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(JsonValue);
 25 
 26     //解析
 27     if (FJsonSerializer::Deserialize(JsonReader, JsonParsed))
 28     {
 29         //从对应数组下标,获取对应类型,对应字段的数据
 30         Culture = JsonParsed[0]->AsObject()->GetStringField(FString("Culture"));
 31         MusicVolume = JsonParsed[1]->AsObject()->GetNumberField(FString("MusicVolume"));
 32         SoundVolume = JsonParsed[2]->AsObject()->GetNumberField(FString("SoundVolume"));
 33 
 34         //获取存档数据
 35         TArray<TSharedPtr<FJsonValue>> RecordDataArray = JsonParsed[3]->AsObject()->GetArrayField(FString("RecordData"));
 36         for (int i = 0; i < RecordDataArray.Num(); ++i)
 37         {
 38             FString RecordDataName = RecordDataArray[i]->AsObject()->GetStringField(FString::FromInt(i));
 39             //保存到
 40             RecordDataList.Add(RecordDataName);
 41         }
 42     }
 43     else
 44     {
 45         SlAiHelper::Debug(FString("Deserialize Failed"));
 46     }
 47 }
 48 
 49 void SlAiJsonHandle::UpdateRecordData(FString Culture, float MusicVolume, float SoundVolume, TArray<FString>* RecordDataList)
 50 {
 51     TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
 52 
 53     //文件最外围是个数组
 54     TArray<TSharedPtr<FJsonValue>> BaseDataArray;
 55     /*
 56     * 实例化一个FJsonObject;通过 SetStringField 传入的 Key 输入对应的参数;将 CultureValue 传入BaseDataArray 需要先将 FJsonObject 类型转换为 FJsonValue
 57     */ 
 58     TSharedPtr<FJsonObject> CultureObject = MakeShareable(new FJsonObject);
 59     CultureObject->SetStringField("Culture", Culture);
 60     TSharedPtr<FJsonValueObject> CultureValue = MakeShareable(new FJsonValueObject(CultureObject));
 61 
 62     TSharedPtr<FJsonObject> MusicVolumeObject = MakeShareable(new FJsonObject);
 63     MusicVolumeObject->SetNumberField("MusicVolume", MusicVolume);
 64     TSharedPtr<FJsonValueObject> MusicVolumeValue = MakeShareable(new FJsonValueObject(MusicVolumeObject));
 65 
 66     TSharedPtr<FJsonObject> SoundVolumeObject = MakeShareable(new FJsonObject);
 67     SoundVolumeObject->SetNumberField("SoundVolume", SoundVolume);
 68     TSharedPtr<FJsonValueObject> SoundVolumeValue = MakeShareable(new FJsonValueObject(SoundVolumeObject));
 69 
 70     //最后一部分还是数组,这里通过一个for循环将字符串转换为Json格式
 71     TArray<TSharedPtr<FJsonValue>> RecordDataArray;
 72     for (int i = 0; i < RecordDataList->Num(); i++)
 73     {
 74         TSharedPtr<FJsonObject> RecordItem = MakeShareable(new FJsonObject);
 75         RecordItem->SetStringField(FString::FromInt(i), (*RecordDataList)[i]);
 76         TSharedPtr<FJsonValueObject> RecordDataValue = MakeShareable(new FJsonValueObject(RecordItem));
 77         RecordDataArray.Add(RecordDataValue);
 78     }
 79     //将数组Json转成Value数据
 80     TSharedPtr<FJsonObject> RecordDataObject = MakeShareable(new FJsonObject);
 81     RecordDataObject->SetArrayField("RecordData", RecordDataArray);
 82     TSharedPtr<FJsonValueObject> RecordDataValue = MakeShareable(new FJsonValueObject(RecordDataObject));
 83 
 84     //加到最大的数组
 85     BaseDataArray.Add(CultureValue);
 86     BaseDataArray.Add(MusicVolumeValue);
 87     BaseDataArray.Add(SoundVolumeValue);
 88     BaseDataArray.Add(RecordDataValue);
 89     
 90     //把数组转换成JsonObject
 91     JsonObject->SetArrayField("T", BaseDataArray);
 92 
 93     //JsonObject转换为字符串
 94     FString JsonStr;
 95     GetFStringInJSonData(JsonObject, JsonStr);
 96 
 97     SlAiHelper::Debug(FString("Origin Str:" + JsonStr), 60.F);
 98 
 99     //去掉多余字符
100     JsonStr.RemoveAt(0, 8);
101     JsonStr.RemoveFromEnd(FString("}"));
102 
103     SlAiHelper::Debug(FString("Final Str:" + JsonStr), 60.F);
104 
105     //写入文件
106     WriteFileWithJsonData(JsonStr, RelativePath, RecordDataFileName);
107 }
108 
109 bool SlAiJsonHandle::LoadStringFromFile(const FString& FileName, const FString& RelaPath, FString& ResultString)
110 {
111     if (!FileName.IsEmpty())
112     {
113         //获取绝对路径 (ProjectContentDir() 是原来的 GameContentDir(), 4.26版本后改名了)
114         FString AbsoPath = FPaths::ProjectContentDir() + RelaPath + FileName;
115 
116         //判断文件是否存在
117         if (FPaths::FileExists(AbsoPath))
118         {
119             if (FFileHelper::LoadFileToString(ResultString, *AbsoPath))
120             {
121                 return true;
122             }
123             else
124             {
125                 //加载不成功
126                 SlAiHelper::Debug(FString("Load Error!!") + AbsoPath);
127                 return false;
128             }
129         }
130         else
131         {
132             //输出文件不存在
133             SlAiHelper::Debug(FString("File Not Exist!!") + AbsoPath);
134         }
135     }
136     return false;
137 }
138 
139 bool SlAiJsonHandle::GetFStringInJSonData(const TSharedPtr<FJsonObject>& JsonObj, FString& JsonStr)
140 {
141     if (JsonObj.IsValid() && JsonObj->Values.Num() > 0)
142     {
143         TSharedRef<TJsonWriter<TCHAR>> JsonWriter = TJsonWriterFactory<TCHAR>::Create(&JsonStr);
144         FJsonSerializer::Serialize(JsonObj.ToSharedRef(), JsonWriter);
145         return true;
146     }
147     return false;
148 }
149 
150 bool SlAiJsonHandle::WriteFileWithJsonData(const FString& JsonStr, const FString& RelaPath, const FString& FileName)
151 {
152     if (!JsonStr.IsEmpty())    //判断字符串是否为空
153     {
154         if (!FileName.IsEmpty())
155         {
156             FString AbsoPath = FPaths::ProjectContentDir() + RelaPath + FileName;
157             //保存
158             if (FFileHelper::SaveStringToFile(JsonStr, *AbsoPath))
159             {
160                 return true;
161             }
162             else
163             {
164                 SlAiHelper::Debug(FString("Save") + AbsoPath + FString("-->Failed"), 30.f);
165                 return false;
166             }
167         }
168         SlAiHelper::Debug(FString("!FileName.IsEmpty() ==False"), 30.f);
169         return false;
170     }
171     SlAiHelper::Debug(FString("!JsonStr.IsEmpty() ==False"), 30.f);
172     return false;
173 }

 

 

写入的相关方法写完了,然后游戏中在改变语言和声音配置时调用该方法

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     SlAiSingleton<SlAiJsonHandle>::Get()->UpdateRecordData(GetEnumValueAsString<ECultureTeam>(FString("ECultureTeam"), CurrentCulture), MusicVolume, SoundVolume, &RecordDataList);
 61 }
 62 
 63 void SlAiDataHandle::ResetMenuVolume(float MusicVol, float SoundVol)
 64 {
 65     if (MusicVol > 0)
 66     {
 67         MusicVolume = MusicVol;
 68     }
 69     if (SoundVol > 0)
 70     {
 71         SoundVolume = SoundVol;
 72     }
 73     /*
 74     更新存档数据*/
 75     SlAiSingleton<SlAiJsonHandle>::Get()->UpdateRecordData(GetEnumValueAsString<ECultureTeam>(FString("ECultureTeam"), CurrentCulture), MusicVolume, SoundVolume, &RecordDataList);
 76 }
 77 
 78 //根据枚举值返回字符串
 79 template<typename TEnum>
 80 FString SlAiDataHandle::GetEnumValueAsString(const FString& Name, TEnum Value)
 81 {
 82     //通过UE4的FindObject寻找所有ANY_PACKAGE反射到的Name,寻找到后实例化后返回
 83     const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, *Name, true);
 84 
 85     if (!EnumPtr)
 86     {
 87         return FString("InValid");
 88     }
 89     return EnumPtr->GetEnumName((int32)Value);
 90 }
 91 
 92 //根据字符串返回枚举值
 93 template<typename TEnum>
 94 TEnum SlAiDataHandle::GetEnumValueFromString(const FString& Name, FString Value)
 95 {
 96     const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, *Name, true);
 97 
 98     if (!EnumPtr)
 99     {
100         return TEnum(0);
101     }
102     return (TEnum)EnumPtr->GetIndexByName(FName(*FString(Value)));
103 }
104 
105 void SlAiDataHandle::InitRecordData()
106 {
107     //获取语言
108     FString Culture;
109     //使用单例读取存档数据
110     SlAiSingleton<SlAiJsonHandle>::Get()->RecordDataJsonRead(Culture, MusicVolume, SoundVolume, RecordDataList);
111 
112     //初始化语言
113     ChangeLocalizationCulture(GetEnumValueFromString<ECultureTeam>(FString("ECultureTeam"), Culture));
114 }

 

 

 

 

 

 

 

 

 

 

 

========================================================================================================================================

posted @ 2021-09-01 16:33  索智源  阅读(608)  评论(0编辑  收藏  举报