GameSaveLoadScript

来源:互联网 发布:js获取json数组长度 编辑:程序博客网 时间:2024/06/04 00:42

原文链接:如何在Unity中保存并加载玩家的进度
http://www.manew.com/thread-98780-1-1.html





在本教程中,你会了解怎么实现简单的系统,一个创建和管理游戏的系统。我们会创建Final Fantasy般的主菜单框架,能够使玩家创建一个新的,独一无二的保存文件以及加载已经存在的。一些原则表明将允许你将他们扩展到任何需要你的游戏。



在本教程的最后,我们会学到这些:


Unity3D使用序列化来保存并加载游戏数据


在整个场景的变化过程中使用静态变量保存数据


注:在所有平台上除了网络播放器都使用这种方法保存和加载游戏数据。web播放器保存游戏数据的信息,可以看看官方文档and browser communication。
Let's Get Serial

我们将要做的第一件事就是创建一些代码,能够允许我们序列化游戏数据,将它转换一个格式,使其能够被保存后再恢复。为此,让我们创建一个C #脚本并命名为SaveLoad。这个脚本将处理所有的保存和加载功能。


我们会从其他脚本中引用这个脚本,所以让我们通过在public和class之间添加static,把它变成一个静态的类。让我们也删除:MonoBehaviour的一部分,因为我们不需要将它附加到一个游戏对象。因为它不再继承MonoBehaviour,让我们删除启动和更新功能。


最后的代码应该看起来像这样:
[AppleScript] 纯文本查看 复制代码
?
 
1
2
3
4
5
        usingUnityEngine;
usingSystem.Collections;
  
publicstaticclassSaveLoad {
  
}




现在,我们想要在这个脚本中添加一些新的函数,所以在usingSystem.Collections下面添加以下这些:


[AppleScript] 纯文本查看 复制代码
?
 
1
2
usingSystem.Collections.Generic;
usingSystem.Runtime.Serialization.Formatters.Binary;
usingSystem.IO;







第一行允许我们使用C #创建的动态列表,但这是不必要的序列化。第二行我们能够使用脚本中的操作系统的序列化功能。在第三行中,IO代表输入/输出,并允许我们从计算机或移动设备上写和读。换句话说,这条线允许我们创建独特的文件,然后从这些文件中读取。


现在我们准备序列化一些数据。


Making SerializableClasses 创建序列化类

现在我们脚本已经有序列化的能力,我们要创建一些被序列化的类。如果考虑简单的RPG游戏,例如最终幻想,它为玩家提供了创建和加载不同的游戏保存方式。因此,创建一个新的C #脚本并命名为Game,给它一些变量来保存三个对象:一个knight,一个rogue,和一个wizard。改变脚本的代码,最后使其看起来像这样:

[AppleScript] 纯文本查看 复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
usingUnityEngine;
usingSystem.Collections;
  
[System.Serializable]
publicclassGame {
  
    publicstaticGame current;
    publicCharacter knight;
    publicCharacter rogue;
    publicCharacter wizard;
  
    publicGame () {
        knight = newCharacter();
        rogue =newCharacter();
        wizard = newCharacter();
    }
          
}



[System.Serializable]这行告诉Unity脚本可以被序列化,换句话说,我们在这个脚本可以保存所有的变量。根据官方文档,Unity可以序列化以下类型:



  • 所有简单的数据类型

  • 一些内建类型(包括Vector2, Vector3, Vector4, Quaternion, Matrix4x4, Color, Rect,以及LayerMask)

  • 继承于UnityEngine.Object的所有类 (包括GameObject, Component, MonoBehavior, Texture2D, 以及 AnimationClip )。

  • Enums. 枚举

  • Arrays and lists of a serializable type. 数组以及序列类型的清单


第一个变量,current是对Game实例的静态引用。当我们创建或者加载一个游戏,我们将把静态变量设置为独有的游戏实例,以便于我们从工程的任何地方引用这个变量。通过使用静态变量和函数,我们不必要使用一个gameObject的GetComponent()函数。


Notice that it'sreferencing something called a Character? Wedon't have that yet, so let's create a new script to house this class, and callit Character:
注意它引用的是一个被称为Character的事物?我们还没有它,让我们创建一个新的脚本来管理这个类,并命名为Character:

[AppleScript] 纯文本查看 复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
usingUnityEngine;
usingSystem.Collections;
  
[System.Serializable]
publicclassCharacter {
  
    publicstringname;
  
    publicCharacter () {
        this.name= "";
    }
}



你可能会想知道,如果我们只是存储一个字符串变量,为什么需要一个全新的类。事实上,我们可以取代在Game 脚本中使用string代替character。但我想告诉你,这个方法能怎么用:你可以引用其他类来保存和加载类,等等,只要各个类已经序列化。


现在,我们的类设置为可以保存和加载的,让我们跳回到我们的SaveLoad 脚本并添加保存游戏的能力。


Saving a Game's State保存一种游戏状态

一个"Load Game"菜单通常会展示保存好的游戏清单,所以让我们创建一个列表类型的游戏并命名为savedGames。使它成为static List类型,这样我们的项目中只有一个保存的游戏列表。代码应该看起来像这样:


[AppleScript] 纯文本查看 复制代码
?
 
01
02
03
04
05
06
07
08
09
10
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
usingSystem.Runtime.Serialization.Formatters.Binary;
usingSystem.IO;
  
publicstaticclassSaveLoad {
  
    publicstaticList<Game>savedGames = newList<Game>();
  
}




接下来,让我们创建一个新的静态函数来保存游戏:
[AppleScript] 纯文本查看 复制代码
?
 
1
2
3
4
5
6
publicstaticvoidSave(){
    savedGames.Add(Game.current);
    BinaryFormatter bf = newBinaryFormatter();
    FileStream file= File.Create (Application.persistentDataPath+ "/savedGames.gd");
    bf.Serialize(file,SaveLoad.savedGames);
    file.Close();
}



第2行将我们当前的游戏添加到保存的游戏列表中。这个名单是我们要序列化的。为此,我们首先需要创建一个新的BinaryFormatter,它将处理序列化工作。这是第3行做的。


第四行,我们正在创建一个FileStream,它本质上是一个新文件的路径,我们可以发送数据 ,就像鱼在河下游泳。我们使用File.Create()来创建一个新文件,它的位置作为我们传过去的参数。 Unity有一个内置的location来存储我们的游戏文件(即基于游戏平台自动更新),我们可以参考使用Application.persistentdatapath。


由于我们正在创建一个新文件,但是,我们不能仅仅只说文件在哪里,我们也必须用实际文件本身的名称来关闭这个路径。这个文件有两个部分:


  • 文件名字
  • 文件类型


我们将使用savedgames作为文件名,我们会使用自定义数据类型gd(“游戏数据”)作为文件类型。我们的结果在设定位置application.persistentdatapath的游戏文件savedgames.gd中。(将来,你可以使用这个数据类型保存其他类型的东西;例如,你可以将用户选项设置保存为options.gd。)



注意:你可以使用任何你想要的文件类型。例如,the Elder Scrolls系列使用.esm作为文件类型。你也可以简单的保存为savedgames.baconandgravy。


第5行中,我们调用BinaryFormatter函数的Serialize功能将savedGames列表保存到我们的新文件中。之后,在第6行关闭创建的文件。


我们的游戏保存好了。


Loading a Game's State加载一种游戏状态
在Save函数,我们在一个特定的位置序列化已保存的游戏列表。相反,加载游戏的代码应该是这样的:

[AppleScript] 纯文本查看 复制代码
?
 
1
2
3
4
5
6
7
publicstaticvoidLoad(){
    if(File.Exists(Application.persistentDataPath+ "/savedGames.gd")) {
        BinaryFormatter bf= newBinaryFormatter();
        FileStream file = File.Open(Application.persistentDataPath+ "/savedGames.gd", FileMode.Open);
        SaveLoad.savedGames= (List<Game>)bf.Deserialize(file);
        file.Close();
    }
}



在第2行中,我们检查保存的游戏文件是否存在.。(如果没有,很明显没有东西可以加载。)在3行,使用处理Save函数的相同方式来创建一个BinaryFormatter。第4行中,我们创建一个FileStream,但是这一次,我们目标从文件流相反方向移动。因此,我们使用file.Open,并表明savedgames.gd存在的地方使用相同的application.persistentdatapath字符串。


第五行有点多,所以让我们展开他



  • bf.Deserialize(文件)回调在我们上面指定位置找到文件并反序列化它。



  • 我们不能只是在Unity中指望二进制并期望它工作,但是,(将我们反序列化文件转换(计算)成我们想要的数据类型,在这种情况下它是一个列表的类型



  • 然后将列设置为我保存的游戏列表。


最后,在第六行,和在Save函数里做过得一样,以同种方式关闭文件。


注:你转换反序列化的数据类型可以根据你的需要改变。例如,Player.lives = (int)bf.Deserialize(file)。


Conclusion 结论


我们的SaveLoad脚本已经完成,应该像这样:

这是保存和加载Unity的基础知识.。在the attachedproject file中,你会发现一些其他脚本,展示我如何处理调用这些函数,以及如何使用Unity的GUI来显示数据.。


如果你需要让你你的游戏开发有一些优势,可在Envato市场尝试Unity3D templates。
0 0
原创粉丝点击