最开始看到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)