序列化技术:
序列化 就是把一个内存对象变为与地址无关的可传输的数据格式,通常是文本格式;反序列化反之。
一般情况下,对象序列化指把一个对象用 XML,YAML 或 json 文本表示。 尽管 Unity 场景文件是 yaml 格式的,但并没有提供运行时内置支持。
Unity 已内置 json 支持。
在U3D中使用Serializable标签来标识可序列化对象
[Serializable]
public class MyClass
{
public int level;
public float timeElapsed;
public string playerName;
}
在一个 monoBehavior 中,添加上述类,[Serializable]标签,说明这个类可以被序列化。
U3D中内置了JsonUtility类,用于支持对象的序列化与反序列化,这个类主要包括三个方法
- FromJson 用 Json 数据实例化一个新对象
- FromJsonOverwrite 用 Json 数据重新赋值一个对象
- ToJson 将对象变成一个字符串
下面具体讲一下利用序列化技术发布新的游戏版本
我们采用之前做得飞碟设计游戏作为例子
每次开始游戏之前会读取远程控制目录的游戏版本文件,如果发现与当前的版本不一致就会更新游戏,如果游戏版本没变,则会进入到上次退出游戏时的状态,能够看到上次退出时的分数和轮数
首先是远程控制目录,我设置的是D:\UnityVersionData文件夹
每个版本的文件夹下面有多个json文件,包括一个game_info文件和多个disk_level文件
game_info文件包含游戏的版本号以及当前总的轮数:
disk_info文件包括每一轮游戏的各种设置参数,例如射出的飞碟数,飞碟颜色,初速度,入射角度等
新建C#脚本,用于版本控制
声明用于序列化的对象
[Serializable]
public class GameInfo : System.Object {
public string version;
public int totalRound;
}
[Serializable]
public class LevelInfo:System.Object {
public int round;
public int UFO_total_num;
public string color;
public float disk_scale;
public float speed;
public float lanuch_position_Y;
public float lanuch_angle;
}
这两个对象分别对应json文件里的对象(注意,这里的对象类型必须是JsonUtility能够解析的对象类型,主要是各种基础类型,如果有类成员变量,需要将这个类单独进行序列化,不然无法解析)
声明一个版本管理类,使用单例模式,用于管理版本信息
public class DictManager : System.Object {
private static DictManager _instance;
private static readonly string gameversion = "version";
private static readonly string gameround = "totalRound";
//最多10轮
private static readonly string[] disk_level = new string[]{
"disk_level_1", "disk_level_2", "disk_level_3",
"disk_level_4", "disk_level_5", "disk_level_6", "disk_level_7", "disk_level_8", "disk_level_9", "disk_level_10"};
private static readonly string currentRound = "currentRound";
private static readonly string currentScore = "currentScore";
public static DictManager getInstance() {
if (_instance == null)
_instance = new DictManager ();
return _instance;
}
//保存版本信息
public void setVersion(string version) {
PlayerPrefs.SetString (gameversion, version);
}
public string getVersion() {
return PlayerPrefs.GetString(gameversion, "none");
}
//保存总的游戏轮数
public void setTotalGround(int totalRound) {
PlayerPrefs.SetInt (gameround, totalRound);
}
public int getTotalRound() {
return PlayerPrefs.GetInt (gameround, 0);
}
//保存当前轮数的游戏信息
public void setLevelInfo(int index, string text) {
PlayerPrefs.SetString (disk_level [index], text);
}
public void cleanLevelInfo(int index) {
while (index < 10 && PlayerPrefs.HasKey (disk_level [index])) {
PlayerPrefs.DeleteKey (disk_level [index]);
index++;
}
}
public string getLevelInfo(int index) {
return PlayerPrefs.GetString (disk_level [index], "none");
}
//保存当前轮数
public void setCurrentRound(int Round) {
PlayerPrefs.SetInt (currentRound, Round);
}
public int getCurrentRound() {
return PlayerPrefs.GetInt (currentRound);
}
//保存当前分数
public void setCurrentScore(int Score) {
PlayerPrefs.SetInt (currentScore, Score);
}
public int getCurrentScore() {
return PlayerPrefs.GetInt (currentScore);
}
}
这个管理类中使用了PlayerPrefs类,他的作用是保存游戏Session之间的数据,从代码中可以发现,这个其实就是一个字典,他以key-value的方式持久化数据,一般来说,这个类适合用来存储与现场恢复相关的数据,类似于web开发中的session和cookie,关于PlayerPrefs类的具体用法可以参考
http://docs.unity3d.com/ScriptReference/PlayerPrefs.html
注意到这里使用了一个单例类来管理这个字典,并且字典是注入式的,这样就很好的解决了字典的同步问题,也降低了代码的耦合度,这里采用了OO设计原则
接下来是关于json文件加载,这里使用MonoBehavior的类来加载文件
这里需要使用WWW类,这是一个万能类,支持HTTP,HTTPS, file, jar:file等协议,由于加载文件属于IO操作(如果使用HTTP等协议还可能是网络操作),所以会阻塞当前线程,显然我们不能在主线程里面加载,但是U3D又不能像JAVA一样支持多进程多线程,那怎么办呢?当然是使用协程了!协程可以显式的调用中断,我们只要在加载文件出设置中断就可以了,直到