Unity3D学习(16)之初识DDD

最开始看到DDD是不是一脸懵逼?DDD其实是 Data Driven Design,也就是数据驱动设计。通过数据驱动设计,使得游戏代码更加稳固 (robustness)。我们可以通过改变数据,实现游戏规则、 场景布局、游戏难度的动态改变,而不要程序员的参与。 让游戏发布后,运维与设计师进行”后设计” (Post-Design) 成为可能。

之前关卡的数据都是通过写在代码中实现的

 switch (round)
        {
            case 1:
                diskData.size = 0.8f;//设置大小
                diskData.color = Color.green;//设置颜色
                newDisk.transform.localScale = new Vector3(25 * diskData.size, 25 * diskData.size, 25 * diskData.size);
                newDisk.GetComponent<Renderer>().material.color = diskData.color;
                break;
            case 2:
                diskData.size = 0.7f;//设置大小
                diskData.color = Color.yellow;//设置颜色
                newDisk.transform.localScale = new Vector3(25 * diskData.size, 25 * diskData.size, 25 * diskData.size);
                newDisk.GetComponent<Renderer>().material.color = diskData.color;
                break;
            case 3:
                diskData.size = 0.6f;//设置大小
                diskData.color = Color.red;//设置颜色
                newDisk.transform.localScale = new Vector3(25 * diskData.size, 25 * diskData.size, 25 * diskData.size);
                newDisk.GetComponent<Renderer>().material.color = diskData.color;
                break;
        }

现在我们将数据保存在Json文件中去,在Asset文件夹下新建Data文件夹,然后新建Disk_Level_1.Json, Disk_Level_2.Json,Disk_Level_3.Json 和Game_Info.Json如下,把我们的数据写进文件里

然后新建一个FileManager.cs用于读取游戏版本及其关卡文件。

public class FileManager : MonoBehaviour {
    public string url;
    public SceneController sceneControler { get; set; }
    // Use this for initialization
    void Awake () {
        //print(Application.persistentDataPath);
        sceneControler = (SceneController)SSDirector.getInstance().currentScenceController;
        sceneControler.fileManager = this;
        LoadGameInfoJson("game_info.json");
    }
	
	// Update is called once per frame
	void Update () {
		
	}

    // 输入游戏信息文件名,启动协程读取文件  
    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
                sceneControler.stageGameInfo(www.text.ToString());   // 返回json字符串给scene  
        }
    }                                                                                               //输入游戏关卡文件名,启动协程读取文件
    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
                sceneControler.stageLevel(www.text.ToString());  // 返回json字符串给scene  
        }
    }
}


然后写两个可序列化的类用于保存游戏版本信息和关卡信息

[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 float size;//飞碟大小
    public string color;//飞碟颜色
    public float speed;//飞碟速度

    public static LevelData CreateFromJSON(string json)
    {
        return JsonUtility.FromJson<LevelData>(json);
    }
}

在SceneController里面添加两个变量保存游戏版本及关卡总数

public string _version;//版本号
public int _totalRound;//总共轮数


由于FileManager读取了版本信息后调用了scene.stageGameInfo,所以相应地在sceneController中添加该方法,接收 json 字符串:

public void stageGameInfo(string json)
    {
        UpdateData = GameInfo.CreateFromJSON(json);
        _version = UpdateData.version;
        _totalRound = UpdateData.totalRound;
    }


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

public void nextRound()
    {
        if(++round > _totalRound)
        {
            round = 1;
        }
        string file = "Disk_Level_" + round.ToString() + ".json";
        fileManager.loadLevelJson(file);
    }

然后在sceneController中添加 stageLevel 方法接收json字符串,更新关卡:

public void stageLevel(string json)
    {
        LevelData data = LevelData.CreateFromJSON(json);
        Color _color;
        if (!ColorUtility.TryParseHtmlString(data.color, out _color))
        {
            _color = Color.gray;
        }                                                                                               //所有更新的关卡信息全部保存在预制中,工厂制造飞碟根据预制
        factory.diskPrefab.GetComponent<DiskData2>().color = _color;
        factory.diskPrefab.GetComponent<DiskData2>().size = data.size;
        factory.diskPrefab.GetComponent<DiskData2>().speed = data.speed;
    }


然后实现联网检查更新,首先用node搭建服务器(有点对不起王青爸爸的教诲,已经忘了怎么做,于是重头来过)

var http = require('http');
var url=require('url');
var fs=require('fs');
var server = http.createServer(function(req,res){
	if(url.parse(req.url).pathname == "/") {
		res.writeHead(200, {'Content-type' : 'text/plain'});
		res.write("2.0");//当前服务器最新游戏版本号
		res.end();
	}
	if(url.parse(req.url).pathname == "/version") {
		//res.writeHead(200, {'Content-type' : 'text/plain'});
		res.write(fs.readFileSync("version.json"));//读取版本文件
		res.end();
	}
	if(url.parse(req.url).pathname == "/Disk_Level_1") {
		//res.writeHead(200, {'Content-type' : 'text/plain'});
		res.write(fs.readFileSync("Disk_Level_1.json"));//读取关卡1的文件
		res.end();
	}
	if(url.parse(req.url).pathname == "/Disk_Level_2") {
		//res.writeHead(200, {'Content-type' : 'text/plain'});
		res.write(fs.readFileSync("Disk_Level_2.json"));//读取关卡2的文件
		res.end();
	}
	if(url.parse(req.url).pathname == "/Disk_Level_3") {
		//res.writeHead(200, {'Content-type' : 'text/plain'});
		res.write(fs.readFileSync("Disk_Level_3.json"));//读取关卡3的文件
		res.end();
	}
});
server.listen(1337,"localhost",function(){ //端口号1337
 console.log("listened");//启动时在命令行打印
});


文件目录如下:

启动服务器


然后在场景控制者写 checkUpdate()检查更新

public void checkUpdate()
    {
        string checkUrl = "http://localhost:1337/";
        this.StartCoroutine(checkVersion(checkUrl));
    }

    IEnumerator checkVersion(string url)
    {
        WWW www = new WWW(url);
        yield return www;
        Debug.Log(www.text.ToString());
        if (_version != www.text.ToString() && www.text.ToString() != "")
        {
            updateManager.OpenPanel();//如果版本号不相同,则弹出提示窗口
        }
    }

然后建立提示框,一个panel里面加了两个Button,一个text

制作个进入与退出的动画,然后写UpdateManager.cs

public class UpdateManager : MonoBehaviour {
    public GameObject UpdatePanel;
    public SceneController sceneControler { get; set; }
    void Awake()
    {
        sceneControler = (SceneController)SSDirector.getInstance().currentScenceController;
        sceneControler.updateManager = this;
    }
    public void OpenPanel()
    {
        UpdatePanel.SetActive(true);//激活提示框
    }
    public void ClosePanel()
    {
        UpdatePanel.GetComponent<Animator>().SetBool("Open", false);//播放关闭动画
        StartCoroutine(CloseDelay());//启动协程,让动画播放完再灭活
    }

    public IEnumerator CloseDelay()
    {
        int CoolTimes = 1;
        while (CoolTimes > 0)
        {
            print("还剩" + CoolTimes);
            yield return new WaitForSeconds(1);
            CoolTimes--;
        }
        UpdatePanel.SetActive(false);//灭活
    }
}

点击Yes按钮除了面板退出还会调用Update1更新文件

public void Update1()
    {
        StartCoroutine(UpdateVersion());
    }
    IEnumerator UpdateVersion()
    {
        completeLoad = false;//未完成下载
        updateFile = true;//更新文件中
        string updateUrl = "http://localhost:1337/version"; //服务器网址
        loadJson(updateUrl);
        while (!completeLoad)
        {
            yield return null;
        }
        this.StartCoroutine(writeFile());
    }
    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();
        GameInfo data = GameInfo.CreateFromJSON(json);
        UpdateData = data;
        _version = data.version;//将更新的版本同步到游戏
        _totalRound = data.totalRound;//将更新的总轮数同步到游戏
        completeLoad = true;//完成下载
    }
IEnumerator writeFile()//写入文件
    {
        string jsonUrl = "Assets/Data/Game_Info.json";
        StreamWriter sw;
        sw = new StreamWriter(jsonUrl, false);
        string json = JsonUtility.ToJson(UpdateData);
        sw.WriteLine(json);//写入流
        sw.Close();//关闭流
        sw.Dispose();//销毁流
        yield return null;
        updateFile = false;//更新完毕
    }


如果需要更新,弹出提示框

如果不需要更新,就直接进入游戏

当然如果想要真正发布,需要改一改的,使用PersistentDataPath去读写文件,以PC端为例

print(Application.persistentDataPath);

打印的结果如下


还有很多不懂的,等我懂了再写深入

参考博客Unity3D学习笔记(10)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值