Code Control MVC框架-保存和加载模型

来源:互联网 发布:淘宝授权书psd模板 编辑:程序博客网 时间:2024/05/21 06:23

蛮牛地址:http://www.manew.com/thread-50564-1-1.html
官方地址:http://unitycodecontrol.com/tutorials/
一下内容根据自身理解,以及原文重新翻译了教程文档。并修复了其中我认为的一些错误。

Code Control MVC框架-保存和加载模型

介绍

把对象的数据分离到模型类的其中一个最大的原因是这样它就可以被轻易地保存和加载了。这篇教程会展示其工作原理!

如果这是你第一次使用Code Control我们建议你从第1篇开始读。

Saving a Model 保存模型

当我们在玩游戏的时候我们想要能够停止,关闭我们的设备并且再开始游戏的时候就在我们离开时候的地方(意思就是要有随时保存游戏进度的功能)。在Code Control里面,这是通过保存我们的模型来完成的。接下来的例子会展示怎么做。

public class GameExample {    private void Awake() {        //Instantiate a PersonModel named Peter        //实例化一个叫做Peter的人物模型        PersonModel m = new PersonModel();        m.Name = "Peter";        // Instantiate a PersonController using the model        //实例化一个使用这个模型的PersonController控制器        Controller.Instantiate<PersonController, PersonModel>(m);    }    private void OnSaveButtonClicked() {        // Save all existing models into the "save/" directory        //将所有存在的模型保存进"save/"目录下        Model.SaveAll("save");    }}

在Awake()里面我们用一个叫做Peter的PersonModel模型实例化一个PersonController控制器。当OnSaveButtonClicked() 被调用,我们使用Model.SaveAll()方法来保存所有现存的模型到“save/”目录下。如果我们要检查,我们会在那里找到两个xml文件。一个是为PersonModel保存数据的,另一个作为Code Control用来内部查找模型的清单。

Loading a Model 加载模型

保存只是完成了一半工作,如果我们想要继续玩游戏我们需要加载存储。接下来的例子会展示如何加载和构造我们的游戏。

public class GameExample {    /* Previous code 我是之前的代码*/    private void OnLoadButtonClicked() {        // Delete all existing models, destroying their associated controllers        //删除所有现存的模型,摧毁和它们相关的控制器        Model.DeleteAll();        // Load all models stored in the "save/" directory        //加载保存在"save/"目录下的所有的模型        Model.Load("save", OnLoadStart, OnLoadProgress, OnLoadDone, OnLoadError);    }    private void OnLoadStart() {        /* Loading process begins! 开始加载!*/    }    private void OnLoadProgress(float progress) {        /* The progress parameter outputs the progression on a scale of 0.0f to 1.0f */        /*进度progress参数在 0.0f 到 1.0f的范围内输出加载的进度*/    }    private void OnLoadError(string error) {        /* The error parameter outpus the reason of the error */        /* 错误error参数输出错误的原因*/    }    private void OnLoadDone() {        /* Loading process is done! 加载进度完成!*/        // Retrieve the PersonModel         //检索PersonModel模型        PersonModel m = Model.First<PersonModel>();        // Instantiate the PersonController        //实例化PersonController控制器        Controller.Instantiate<PersonController, PersonModel>(m);    }}

当OnLoadButtonClicked() 被调用的时候,我们以摧毁所有现存的模型开始。我们这样做来确保我们不会得到两个实例化的人,这是有可能在游戏的进程中加载游戏时候发生的。接下来我们使用Model.Load()来加载所有保存在“save/”目录下的模型。Code Control采用异步加载来防止游戏在加载的时候卡死,所以我们指派了一系列的方法来处理加载开始,加载过程,加载完成和加载错误回调函数。

OnLoadDone方法在模型完成加载的时候被调用。这就是我们可以重构游戏的地方。我们使用Model.First这里写图片描述()来检索PersonModel,它会返回它能找到的所给类型的第一个模型。使用这个模型我们实例化PersonController控制器(在其实例化过程中将会用到PersonModel)。我们成功地恢复了游戏!欧耶!

Model Referencing 模型引用

让我们更进一步。有时候模型会需要相互引用。在我们的例子中,一个人可以有一个朋友(也是一个人)。让咱们看看如何使用 Code Control的 ModelRef 类在我们的PersonModel内引用一个模型。

public class PersonModel : Model {    public string Name;    public ModelRef<PersonModel> Friend;}

我们在PersonModel 模型中使用ModelRef 类声明了Friend字段,同时给与了它的朋友一个可保存和可加载的引用。咱们来瞧瞧当我们和我们的新朋友构造游戏的时候我们的新的Awake()方法是怎样的。

public class GameExample {    private void Awake() {        // Instantiate our Peter PersonModel                //实例化我们的Peter君        PersonModel peterModel = new PersonModel();        peterModel.Name = "Peter";        // Instantiate our new Jim PersonModel                //实例化我们的Jim君        PersonModel jimModel = new PersonModel();        jimModel.Name = "Jim";        // Assign each other as friends                //指派它们成为彼此的朋友        peterModel.Friend = new ModelRef<PersonModel>(jimModel);        jimModel.Friend = new ModelRef<PersonModel>(peterModel);        // Construct both controllers                 //构造它们的控制器        Controller.Instantiate<PersonController, PersonModel>(peterModel);        Controller.Instantiate<PersonController, PersonModel>(jimModel);            }    /* Previous Code 之前的代码 */}

我们以实例化两个模型为开始,一个是Peter,另一个是Jim。接下来我们用ModelRef字段来指派它们成为朋友。最后,我们为它们分别实例化了一个控制器。

ModelRef的序列化有什么东西这么特别的?

通常序列化的大问题就是引用。在正常的序列化中,一个相同的模型有多个引用会为每一个引用生成一个独立的序列化模型。在解序列化时这会造成每一个引用生成一个新的模型,尽管在序列化的时候它是唯一 一个。Code Control通过确保每一个模型是单独地被保存的来解决此问题,并使模型通过ModelRef(s)来引用。当保存成套模型的时候,这些ModelRef(s)只序列化它们模型的id。当加载的时候,Code Control首先解序列化和实例化模型,并且只有那个时候才会用对得上号的实例化好的模型来移植所有的ModelRef(s)引用。

为了加载我们新的配套模型,我们需要改变我们正在重构我们游戏的方式。我们不止有一个朋友,所以我们再也不能简单地使用 Model.First()。取而代之,我们将会遍历所有的PersonModels模型并为所有的模型实例化一个新的控制器。

public class GameExample {    /* Previous code 我是之前的代码 */    private void OnLoadDone() {        // Retrieve all PersonModels        //检索所有的模型        List<PersonModel> models = Model.GetAll<PersonModel>();        // Instantiate a controller for each model        //为每一个模型实例化一个控制器        foreach (PersonModel m in models) {            Controller.Instantiate<PersonController, PersonModel>(m);        }    }}

我们使用Model.GetAll这里写图片描述()方法来检索所有的PersonModels模型,该方法会返回它所能找到所有指定类型的模型的一个列表。接下来我们遍历所有找到的模型并为它们分别实例化一个控制器。我们无需担心寻找PersonModel的朋友引用,因为Code Control会搞定所有的一切的!举个例子,Peter君的PersonController现在能够访问他的朋友并发送一个像“嘿,吉姆!”的消息。

Referencing a list of Models 引用模型列表

有时候一个单一的引用对应一个单一模型是不够的。也许在我们游戏里面的人物需要不止一个朋友,也许甚至是一大堆朋友!这就是ModelRefs派上用场的地方。我们新的PersonModel会看起来有一点点不一样。

public class PersonModel : Model {    public string Name;    public ModelRefs<PersonModel> Friends;}

我们现在用ModelRefs(它基本上是PersonModels的一系列引用)来替代ModelRef。一起来瞅瞅当又增加另个人时我们新的Awake()看起来是什么样!

public class GameExample {    private void Awake() {        // Instantiate our Peter PersonModel        //实例化我们的Peter君        PersonModel peterModel = new PersonModel();        peterModel.Name = "Peter";        // Instantiate our Jim PersonModel        //实例化我们的Jim桑        PersonModel jimModel = new PersonModel();        jimModel.Name = "Jim";        // Instantiate our new Alice PersonModel        //实例化我们新的艾莉丝小萝莉        PersonModel aliceModel = new PersonModel();        aliceModel.Name = "Alice";        // Assign Jim and Alice as friends of Peter        //指派Jim和艾莉丝作为Peter的朋友        peterModel.Friends = new ModelRefs<PersonModel>();        peterModel.Friends.Add(jimModel);        peterModel.Friends.Add(aliceModel);        // Assign Peter as friend of Jim and Alice        //指派Peter作为艾莉丝和吉姆的朋友        jimModel.Friends = new ModelRefs<PersonModel>() { peterModel };        aliceModel.Friends = new ModelRefs<PersonModel>() { peterModel };        // Construct controllers        //构造控制层        Controller.Instantiate<PersonController, PersonModel>(peterModel);        Controller.Instantiate<PersonController, PersonModel>(jimModel);        Controller.Instantiate<PersonController, PersonModel>(aliceModel);    }    /* Previous code 我是之前的代码*/}

在实例化我们的三个人物后,我们使用Add()方法指派Jim和Alice到Peter的朋友列表里面去。注意ModelRefs可以理解成一个普通的列表,所以我们指派Peter作为Jim和Alice使用了内联实例化。我们也能够在foreach循环里面遍历ModelRefs并使用其他的你能期望在一个列表里面使用的函数。

这是所有我们需要改变我们代码的地方,因为加载过程保持和原来一样!

Using ModelBlobs 使用模型二进制数据块

我们已经看过怎样以xml的形式在一个指定的文件目录下来保存和加载一大堆的模型,但是有时候我们想要发送我们保存的数据在一个服务器里面或使用别的技术。这就是Code Control的模型二进制数据块闪亮登场的地方了!咱们看看如果我们采用模型二进制数据块来保存和加载是怎样的。

public class GameExample {    /* Previous code 我是之前的代码*/    private void OnSaveButtonClicked() {        // Store all models into modelBlobs        //把所有的模型都保存到模型二进制数据块中        ModelBlobs modelBlobs = Model.SaveAll();        // Convert modelBlobs into a joined string        //将二进制数据块转换成一个连接字符串        string dataString = modelBlobs.ToString();        /* Upload our dataString to a database */        /*上传我们的dataString到一个数据库*/    }    private void OnLoadButtonClicked() {        // Delete all existing models, destroying their associated controllers        //删除所有现存的模型,摧毁它们对应的控制层        Model.DeleteAll();        /* Download our dataString from a database */        /*从一个数据库下载我们的dataString*/        // Convert the downloaded dataString into ModelBlobs        //转换已下载的dataString成模型二进制数据块        ModelBlobs modelBlobs = ModelBlobs.FromString(dataString);        // Load our models using ModelBlobs        //使用二进制数据块加载我们的模型        Model.Load(modelBlobs, OnLoadStart, OnLoadProgress, OnLoadDone, OnLoadError);        /* Previous code 我是之前的代码*/    }    /* Previous code 我也是之前的代码 */}

我们使用Model.SaveAll()方法以一个ModelBlobs对象来保存所有的模型。然后我们在我们modelBlobs 上调用ToString() 方法来把数据转换成一个连接字符串(它接下来会被上传到一个数据库)。需要注意的是数据是通过~字符来连接的。如果你想要自定义一套字符来作为你的dataString的连接符,那么你可以添加它作为ToString()方法的参数。谨记一个单独的字符性能上比多字符更加优异。

要加载我们的模型我们需要从数据库把我们的dataString下载回来。通过dataString的检索,我们才能使用 ModelBlobs.FromString()方法把它转换回ModelBlobs。最后我们使用Model.Load()方法来实例化我们的模型并且当加载完成的时候调用被动方法。

Conclusion 小结

你现在知道该怎么做了!我们保存,加载和重构我们的模型。我们看见一个简单的本地保存技术和覆盖面广且可以灵活保存数据的ModelBlobs的使用。