Unity游戏设计之实现序列化
在游戏设计中,序列化是一件很核心的东西。
序列化就是把一个内存对象变为与地址无关的可传输的数据格式,通常是文本格式。如果游戏没有实现序列化,那么当游戏需要进行版本更新时,将会浪费玩家大量的时间。尤其对于大型游戏来说,这种浪费是不可想象的。实现游戏序列化设计,通过数据驱动设计,使得游戏代码更加稳固 (robustness)。我们可以通过改变数据,实现游戏规则、 场景布局、游戏难度的动态改变,而不要程序员的参与。 让游戏发布后,运维与设计师进行”后设计” (Post-Design) 成为可能。
因此这次我们就来实现一个简单的序列化设计。
步骤:
首先,我们选择的是json文本来实现,因为Unity已内置json支持。
我们将需要的json文本,放入到Assets下的data(自建)文件夹中。
因为我们只是一个简单的序列化实现,所以我们要实现的序列化任务是部分,主要实现的是不同关卡中飞碟的特性。
替代的是以下部分:
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; }
此时运行游戏,就可以发现游戏通过读取文档来和之前一样运行了:
我们再通过添加text,和修改useInterface,就可以将版本信息也显示出来。
参考链接:http://blog.csdn.net/simba_scorpio/article/details/51471161