Unity3d-文本控制版打飞碟

序列化 文本控制 json

Posted by SixTeen on May 22, 2016

序列化

先看看序列化的概念:

序列化 就是把一个内存对象变为与地址无关的可传输的数据格式,通常是文本格式;反序列化反之。

所谓的内存对象就是我们游戏运行时,保存在内存中的对象,例如我们在运行时产生的类都是保存在内存中的,序列化就是把这些保存在内存中的数据变成可以传输的文本格式,例如json,xml等等。反序列化则是把json,xml等等的传输文本格式重新转化为内存数据。

改进打飞碟游戏

我之前的打飞碟游戏,所有和场景有关的数据都保存在judge.cs中的Judge类中,然后在GameModel中实例化Judge类,之后所有需要应用到规则的都使用这个实例中的数据。说到这里,我们的改进方案非常简单:将Judge类变成可序列化的类即可。

序列化的格式:

在需要实例化的类上加上[System.Serializable]即可。

[System.Serializable]
public class Judge{
	//....
}

测试

我们在Assets中新建一个文件夹Json,在Json文件夹中新建一个judge.json文件,并加入下面的内容:

{
"totalRound" : 5,
"totalFly" : 10,
"getPoint" : 10,
"flypos" : {"x":-3,"y":-2,"z":-10},
"flyDir" : {"x":1,"y":1,"z":1},
"flyspeed" : 20.0,
"flynum" : 1,
"bulletspeed" : 200.0
}

Vector3在Unity引擎里也是序列化的类型,我们使用嵌套的json可以初始化vector3."flypos" : {"x":-3,"y":-2,"z":-10}

修改GameModel

现在我们已经序列化了Judge,以及编写了一个Json文件,我们现在需要做的就是将GameModel中实例化的Judge改成从Json中反序列化。

	//private Judge judge = new Judge();
	private Judge judge;
    string json;
    private bool completeLoad = false;//是否完成数据的读写

    void loadJson(string url) {
        this.StartCoroutine(getData(url));//使用协程获取数据
    }

    IEnumerator getData(string url) {
        WWW www = new WWW(url);
        yield return www;//成功获取数据后
        json = www.text.ToString();
        judge = JsonUtility.FromJson<Judge>(json);//使用json反序列化一个Judge类
        completeLoad = true;//完成数据读写
    }

	void Awake () {
		//...
	    string jsonUrl = "file://" + Application.dataPath + "/Json/" + "judge.json";
	    loadJson(jsonUrl);//从对应路径中获取json,并实例化judge
	}

	public void Update(){
        if (!completeLoad) { return; }
        //没有完成数据读取则不进行游戏逻辑,因为游戏逻辑中需要用到我们读取的数据
        //...
    }

加入版本号

现在加入一个版本号,用于检测是否需要更新版本。

在Judge类中加入多一个字段:

    [System.Serializable]
	public class Judge{
        //版本号
        public float version;
        //...
    }

在界面中加入:

	
	//点击按钮触发这个检测更新函数
    public void checkUpdate() {
        string checkUrl = "http://localhost:8080/version";
        this.StartCoroutine(updateVersion(checkUrl));
    }

    //通过协程从网站上获取版本号,与本地版本号对比,如果不同,则进行更新
    IEnumerator updateVersion(string url) {
        WWW www = new WWW(url);
        yield return www;
        if(judge.version != www.text.ToString()) {
            completeLoad = false;
            string updateUrl = "http://localhost:8080/Judge";
            loadJson(updateUrl);
        }
    }

版本号连接的信息:

新版本的详细信息:

最终效果:

更新本地文件

最后我们要做的就是将更新后的信息保存到本地文件,我们使用协程完成这个工作。更新过程中退出会造成文件损坏,所以加一个文字提示更新结束。

	using System.IO;

    IEnumerator updateVersion(string url) {
        WWW www = new WWW(url);
        yield return www;
        if(judge.version != www.text.ToString()) {
            completeLoad = false;
            updateFile = true;
            string updateUrl = "http://localhost:8080/Judge";
            loadJson(updateUrl);
            while (!completeLoad) {
                yield return null;
            }//判断是否完成更新,完成更新后写入本地文件
            this.StartCoroutine(writeFile());
        }
    }

    //使用StreamWriter来进行文件覆盖
    IEnumerator writeFile() {
        string jsonUrl = "Assets/Json/" + "judge.json";
        StreamWriter sw;
        sw = new StreamWriter(jsonUrl, false);
        //将新的版本信息转换成json格式的string
        string json = JsonUtility.ToJson(judge);
        //Debug.Log(json);
        //写入流
        sw.WriteLine(json);
        //关闭流
        sw.Close();
        //销毁流
        sw.Dispose();
        yield return null;
        updateFile = false;
    }

    public void Update(){
        if (updateFile) {
            counting.text = "更新中";
        }
    }

效果

更新版本前:

更新版本后:

完整的GameModel和Judge

//judge.cs
using UnityEngine;
using System.Collections;

namespace com.MyJudge{
    [System.Serializable]
	public class Judge{
        //版本号
        public string version;
		//决定总共的轮数
		//决定每一轮的飞碟个数
		//每一个飞碟的得分
		public int totalRound = 5;
		public int totalFly = 10;
		public int getPoint = 10;
		//飞碟发射位置
		public Vector3 flypos = new Vector3(-3,-2,-10);
		//飞碟发射方向
		public Vector3 flyDir = Vector3.one;
		//飞碟发射速度
		public float flyspeed = 5f;
		//飞碟发射数目
		public int flynum = 1;
		//子弹速度
		public float bulletspeed = 200f;
		//新关卡更新属性
		public void updateRound(){
			//flypos = new Vector3 (-2, 1, -10);
			flyDir = Vector3.one;
			flyspeed += 1f;
			getPoint += 10;
		}
	}
}

public class judge : MonoBehaviour {}
//GameModel.cs
using UnityEngine;
using System.Collections;
using com.MyFactory;
using com.MyAction;
using com.MyShootFly;
using com.MyJudge;
using UnityEngine.UI;
using System.IO;

public class GameModel:MonoBehaviour{
	public Text counting;
	public Text Round;
	public Text Score;
    public Text Version;
	public GameObject bullet;
	private Rigidbody rb;
	private int count = 3;
	private float countTime = 0f;
	private float lastcountTime = 0f;
	private Judge judge;
    private bool completeLoad = false;
    private bool updateFile = false;


    void loadJson(string url) {
        this.StartCoroutine(getData(url));
    }

    IEnumerator getData(string url) {
        WWW www = new WWW(url);
        yield return www;
        string json = www.text.ToString();
        judge = JsonUtility.FromJson<Judge>(json);
        completeLoad = true;
    }

    void Awake () {
		//给子弹添加刚体
		rb = bullet.AddComponent<Rigidbody> ();
        string jsonUrl = "file://" + Application.dataPath + "/Json/" + "judge.json";
        loadJson(jsonUrl);
	}

    public void checkUpdate() {
        string checkUrl = "http://localhost:8080/version";
        this.StartCoroutine(updateVersion(checkUrl));
    }

    IEnumerator updateVersion(string url) {
        WWW www = new WWW(url);
        yield return www;
        if(judge.version != www.text.ToString()) {
            completeLoad = false;
            updateFile = true;
            string updateUrl = "http://localhost:8080/Judge";
            loadJson(updateUrl);
            while (!completeLoad) {
                yield return null;
            }
            this.StartCoroutine(writeFile());
        }
    }

    IEnumerator writeFile() {
        string jsonUrl = "Assets/Json/" + "judge.json";
        StreamWriter sw;
        sw = new StreamWriter(jsonUrl, false);
        string json = JsonUtility.ToJson(judge);
        Debug.Log(json);
        sw.WriteLine(json);
        sw.Close();
        sw.Dispose();
        yield return null;
        updateFile = false;
    }

	public void Update(){
        if (updateFile) {
            counting.text = "更新中";
        }
        if (!completeLoad) { return; }
		SceneController sc = SceneController.getInstance ();
		//实时更新回合和分数
		Round.text = "Round:" + sc.getRound ().ToString ();
		Score.text = "Score:" + sc.getScore ().ToString ();
        Version.text = "Version:" + judge.version;
		//如果点击了发射飞碟,那么进行倒计时
		if (sc.counting&&sc.fly == true) {
			countTime += Time.deltaTime;
			counting.text = count.ToString ();
			//每120帧进行一次计数
			if(countTime - lastcountTime > 120*Time.deltaTime){
				lastcountTime = countTime;
				count--;
			}
			//倒数结束时,根据规则产生发射飞碟
			if(count <= 0){
				count = 3;
				sc.launchFly(judge);
				sc.counting = false;
			}
		} else if (!sc.counting) {
			//没有进行倒数时,不显示
			sc.fly = false;
			counting.text = "";
		}
		//点击鼠标左键后进行射击
		if (Input.GetMouseButtonDown (0)&&sc.shooting) {
			shoot ();
		}
		//根据规则不断检查是否符合进入下一轮的条件
		if (sc.init (judge)) {
			judge.updateRound();
		}
	}
	public void shoot(){
		//初始化子弹,将子弹移动到点击处,组装子弹动作,发射
	    bullet.transform.position = gameObject.transform.position;
		bullet.GetComponent<Rigidbody>().velocity = Vector3.zero;
		ActionManager.getInstance ().ApplyBulletAction (bullet,judge);
		Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
		rb.AddForce (ray.direction*judge.bulletspeed, ForceMode.Impulse);
	}
}
1
FIN 5.22/18.57