Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 处理保存文件迁移的最佳方法_C#_Unity3d - Fatal编程技术网

C# 处理保存文件迁移的最佳方法

C# 处理保存文件迁移的最佳方法,c#,unity3d,C#,Unity3d,正如标题所示,我正试图找到处理保存游戏文件迁移的最佳方法,而不是破坏我的整个代码库。从web开发中,我知道了一种上下迁移技术,虽然我看到了如何将它应用到unity中,但我很难弄清楚如何相对容易地使用它 我目前的想法是: 创建一个接口,负责执行上面提到的上下迁移,因此这将是一个责任链,然后我将每个数据类存储在它所尊重的名称空间中。假设我有一些BallData,它包含位置和颜色,所以看起来像这样: 球数据{Vector3位置;颜色;} 然后我决定,我希望它有一个边界颜色,这是加法变化,这很好。 第二

正如标题所示,我正试图找到处理保存游戏文件迁移的最佳方法,而不是破坏我的整个代码库。从web开发中,我知道了一种上下迁移技术,虽然我看到了如何将它应用到unity中,但我很难弄清楚如何相对容易地使用它

我目前的想法是: 创建一个接口,负责执行上面提到的上下迁移,因此这将是一个责任链,然后我将每个数据类存储在它所尊重的名称空间中。假设我有一些BallData,它包含位置和颜色,所以看起来像这样:
球数据{Vector3位置;颜色;}
然后我决定,我希望它有一个边界颜色,这是加法变化,这很好。 第二天,游戏设计师进来说,“我们不再只有边框颜色,这是个坏主意,我们现在有了顶部和底部边框颜色”,一些想象中的100名玩家已经使用了边框颜色功能进行了更新,我说“确定”,并根据每个更改版本将球数据包装到新的命名空间中,现在我以

namespace BallDataV1 {
   BallData { Vector3 Position, Color Color; }
}

namespace BallDataV2 {
   BallData { Vector3 Position, Color Color, Color BorderColor; }
}

namespace BallDataV3 {
   BallData { Vector3 Position, Color Color, Color TopBorderColor; Color BottomBorderColor }
}
因此,每个迁移版本都知道事物的旧结构,并且可以将更改转换为新结构。在本例中,BallDataV2到BallDataV3确切地知道BorderColor不再是一种东西,我们可以将BorderColor放入TopBorderColor tho中。现在有了TopBorderColor和BottomBorderColor字段,每个数据类版本都有名称空间,甚至有一个带有版本后缀的简单类实例都很方便,但是我发现使用它非常困难,特别是因为我已经有大约15个不同的系统需要保存/加载,并且随着游戏的不断变化和发展,数据也会发生变化,这最终会产生大量的代码和数据,特别是因为我的游戏将以alpha版本发布,并等待一系列更新


非常感谢您提前给出任何答案,如果有不清楚的地方请告诉我

我会让版本数据远离我的实际游戏代码。如果您的数据真的那么不稳定,您甚至可以选择不首先为其创建类,而是以动态序列化格式存储这些数据。然后,您可以编写一个序列化程序将内容序列化为文件,并编写一组不同的反序列化程序来说明版本。现在让我们来看一下你的球结构,假设你有一个游戏状态对象,它包含一个球列表

类游戏状态{
列出球;
}
类结构{
矢量3位置;
颜色;
}
现在,您可以使用序列化程序对其进行序列化

公共类序列化程序{
常量字符串序列化版本=“1”;
公共字符串序列化为字符串(游戏状态游戏状态){
//一些将东西转换成字符串的魔法,可能是JSON
}
}
现在,您的savegame文件包含以下内容:

{
   "_serializationVersion": "1"
   balls : [
      {
         "position" : "1,2,5",
         "color" : "#289328"
      },
      {
         "position" : "1,2,5",
         "color" : "#289328"
      }
   ]
}
现在您可以编写一些反序列化程序,将其读回
GameState
对象

类反序列化器{
公共游戏状态反序列化(字符串输入){
//一些json解析的魔术,你得到游戏状态回来
}
}
现在让我们来看一下您的示例,您同时进行了3次迭代,因此您的序列化程序现在看起来如下所示:

公共类序列化程序{
常量字符串序列化版本=“3”;
公共字符串序列化为字符串(游戏状态游戏状态){
//一些将东西转换成字符串的魔法,可能是JSON
}
}
您的游戏代码没有任何更改。它仍然适用于
游戏状态
对象。
反序列化程序现在需要考虑一些版本:

类反序列化器{
公共游戏状态反序列化(字符串输入){
var jsonObject=JSONParser.Parse(输入);
var version=jsonObject.Get(“_serializationVersion”);
如果(版本=“1”){
从Version1(jsonObject)返回Deserialized;
}
如果(版本=“2”){
从Version2(jsonObject)返回Deserialized;
}
如果(版本=“3”){
从版本3(jsonObject)返回Deserialized;
}
}
私有游戏状态从版本1反序列化(JSONObject JSONObject){
}
私有游戏状态从版本2反序列化(JSONObject JSONObject){
}
私有游戏状态从版本3反序列化(JSONObject JSONObject){
}
}
同样,细节隐藏在反序列化程序中。您的游戏代码和序列化程序始终使用最新和最好的版本。反序列化程序处理将加载的游戏迁移到此最新版本。当然,如果你有不止这个简单的例子,你可能会把它放大一点(例如,每个版本有一个反序列化程序,并在你的游戏代码使用的反序列化程序类中聚合它们),例如


类反序列化器{
private List supportedDeserializers=new List();//在此处获取一些实例,例如使用依赖项注入
公共游戏状态反序列化(字符串输入){
var jsonObject=/…与上面的代码相同
var version=/…与上述代码相同;
for(SupportedDeserializer中的var反序列化器){
if(反序列化程序支持版本(版本)){
返回反序列化程序。反序列化(jsonObject);
}
}
}
}
接口序列化程序{
bool CANDESERIALIZE版本(字符串版本);
游戏状态反序列化(JsonObject对象);
}
类v1反序列化程序:IDeserializer{
// ...
}
类V2Deserializer:IDeserializer{
// ...
}
类V3Deserializer:IDeserializer{
// ...
}
这样,您的游戏代码就可以调用主反序列化程序,并且很高兴,您不需要处理域对象的各种版本

当然,在某些情况下,迁移是不可能的,例如,如果您决定从游戏中移除球