在游戏设计中,序列化是一件很核心的东西。

序列化就是把一个内存对象变为与地址无关的可传输的数据格式,通常是文本格式。如果游戏没有实现序列化,那么当游戏需要进行版本更新时,将会浪费玩家大量的时间。尤其对于大型游戏来说,这种浪费是不可想象的。实现游戏序列化设计,通过数据驱动设计,使得游戏代码更加稳固 (robustness)。我们可以通过改变数据,实现游戏规则、 场景布局、游戏难度的动态改变,而不要程序员的参与。 让游戏发布后,运维与设计师进行”后设计” (Post-Design) 成为可能。

因此这次我们就来实现一个简单的序列化设计。

步骤:

首先,我们选择的是json文本来实现,因为Unity已内置json支持。

我们将需要的json文本,放入到Assets下的data(自建)文件夹中。

unity游戏设计流程结构图长什么样 unity简单游戏设计_版本信息

unity游戏设计流程结构图长什么样 unity简单游戏设计_unity游戏设计流程结构图长什么样_02

因为我们只是一个简单的序列化实现,所以我们要实现的序列化任务是部分,主要实现的是不同关卡中飞碟的特性。

替代的是以下部分:



switch (round)  
		{  
		case 0:  
			{  
				newDisk.GetComponent<DiskData>().color = Color.blue;  
				newDisk.GetComponent<DiskData>().speed = 4.0f;  
				float RanX = UnityEngine.Random.Range(-1f, 1f) < 0 ? -1 : 1;  
				newDisk.GetComponent<DiskData>().direction = new Vector3(RanX, 1, 0);  
				newDisk.GetComponent<Renderer>().material.color = Color.blue;  
				break;  
			}  
		case 1:  
			{  
				newDisk.GetComponent<DiskData>().color = Color.red;  
				newDisk.GetComponent<DiskData>().speed = 6.0f;  
				float RanX = UnityEngine.Random.Range(-1f, 1f) < 0 ? -1 : 1;  
				newDisk.GetComponent<DiskData>().direction = new Vector3(RanX, 1, 0);  
				newDisk.GetComponent<Renderer>().material.color = Color.red;  
				break;  
			}  
		case 2:  
			{  
				newDisk.GetComponent<DiskData>().color = Color.black;  
				newDisk.GetComponent<DiskData>().speed = 8.0f;  
				float RanX = UnityEngine.Random.Range(-1f, 1f) < 0 ? -1 : 1;  
				newDisk.GetComponent<DiskData>().direction = new Vector3(RanX, 1, 0);  
				newDisk.GetComponent<Renderer>().material.color = Color.black;  
				break;  
			}  
		}



 现在,我们可以用序列化的方式,来取代它们。

添加两个带有[SerializeField] 符号的类,用来对json数据进行序列化。[Serializable]标签,说明这个类可以被序列化。一个是用来存放关卡信息,另一个用来存放版本信息。json文件的数据要与这个类的内容对应起来:



[SerializeField]  
public class GameInfo  
{  
	public string version;  
	public int totalRound;  
	public static GameInfo CreateFromJSON(string json)  
	{  
		return JsonUtility.FromJson<GameInfo>(json);  
	}  
}  
[SerializeField]  
public class LevelData  
{  
	public string color1;  
	public string color2;
	public float speed;  
	public static LevelData CreateFromJSON(string json)  
	{  
		return JsonUtility.FromJson<LevelData>(json);  
	}  
}



 然后设计读取json文件的FileManager类:



using UnityEngine;  
using System.Collections;  
using Com.Mygame;  
  
public class FileManager : MonoBehaviour {  
    public string url;  
  
    SceneController scene = SceneController.getInstance();  
  
    void Awake()  
    {  
        scene.setFileManager(this); 
        // 获取游戏版本信息 
        LoadGameInfoJson("game_info.json");  
    }  
  
    // 传入文件名,启动协程读取文件  
    public void loadLevelJson(string name)  
    {  
        url = "file://" + Application.dataPath + "/Data/" + name;  
        StartCoroutine(LoadLevel());  
    }  
  
    IEnumerator LoadLevel()  
    {  
        if (url.Length > 0)  
        {  
            WWW www = new WWW(url);  
            yield return www;  
            if (!string.IsNullOrEmpty(www.error))  
                Debug.Log(www.error);  
            else  
                scene.stageLevel(www.text.ToString());  // 返回json字符串给scene  
        }  
    }  
  
    // 传入游戏信息文件名,启动协程读取文件  
    public void LoadGameInfoJson(string name)  
    {  
        url = "file://" + Application.dataPath + "/Data/" + name;  
        StartCoroutine(LoadGameInfo());  
    }  
  
    IEnumerator LoadGameInfo()  
    {  
        if (url.Length > 0)  
        {  
            WWW www = new WWW(url);  
            yield return www;  
            if (!string.IsNullOrEmpty(www.error))  
                Debug.Log(www.error);  
            else  
                scene.stageGameInfo(www.text.ToString());   // 返回json字符串给scene  
        }  
    }  
}



为了记录下版本的信息,以及关卡数,我们需要加多两个变量来存储这两个信息:



private string _version;  
private int _totalRound;



 另外还要修改接口函数信息:



public interface IQueryStatus {
    bool isCounting();
    bool isShooting();
    int getRound();
    int getPoint();
    int getEmitTime();
    int getTotalRound ();
    string getVersion ();
}
public int getTotalRound () {
    return _totalRound;
}
public string getVersion () {
    return _version;
}



 同时,游戏的关卡是游戏过程中读取的,所以修改sceneController的nextRound()方法:



public void nextRound() {  
    _point = 0;  
    if (++_round > _totalRound) {  
        _round = 1; // 循环  
    }  
    string file = "disk_level_" + _round.ToString() + ".json";  
    _fileManager.loadLevelJson(file);
}



 然后,补全stageLevel和stageGameInfo两个序列化json实例后转化为相应的游戏参数的方法:



public void stageLevel(string json) {  
    LevelData data = LevelData.CreateFromJSON(json);  
    Color color1;  
    if (!ColorUtility.TryParseHtmlString(data.color1, out color1)) {  
        color1 = Color.gray;  
    } 
    Color color2;  
    if (!ColorUtility.TryParseHtmlString(data.color2, out color2)) {  
        color2 = Color.gray;  
    } 
    float speed = data.speed;  
    _gameModel.setting(color1, speed, color2);  
}
public void stageGameInfo(string json) {  
    GameInfo info = GameInfo.CreateFromJSON(json);  
    _version = info.version;
    _totalRound = info.totalRound;  
}



 此时运行游戏,就可以发现游戏通过读取文档来和之前一样运行了:

unity游戏设计流程结构图长什么样 unity简单游戏设计_json_03

我们再通过添加text,和修改useInterface,就可以将版本信息也显示出来。

unity游戏设计流程结构图长什么样 unity简单游戏设计_json_04