游戏UI框架设计(五)

--配置管理与应用



在开发企业级游戏/VR/AR产品时候,我们总是希望可以总结出一些通用的技术体系,框架结构等,为简化我们的开发起到“四两拨千金”的作用。所谓“配置管理”是指一个游戏项目(软件项目),很多需要经常变化的需求或者数据,最好以配置文件的形式存在,从而代替“硬编码”方式。


这里笔者就对游戏产品中大量应用到动态加载的情形,开发出一套通用的配置管理(脚本)工具。该工具可以很方便的对于具备“键值对”特性的配置文件做统一的数据提取处理,特别适合如下应用情形等:


1:“UI预设”/“游戏对象预设”的动态加载。

2:企业级Log 日志系统中关于配置信息(日志的保存路径、日志级别信息)的动态加载。

3:资源(语言)国际化系统中关于语言信息的动态加载。


下图给出本UI框架用到的"语言国际化"对应的Json 配置文件:



(“语言国际化”中文信息的Json配置文件)



目前(2017)国际国内普遍采用的配置管理方式主要有两种: XML与Json 方式。

两者各有优缺点:

XML: 对于数据的精确表示、易读性很高。

微软很多的项目都内置对XML作为配置文件的支持。

(例如: 网站项目:ASP.Net、 WinForm 等)

缺点是读写速度慢,这个问题在移动端尤其突出。


Json: 读写速度快,但是易读性没有XML好,但是可以接受。

所以本框架项目都采用Json作为配置文件。



考虑到目前移动端游戏/VR/AR产品的大量应用,所以笔者在此重点介绍基于Json配置文件的数据解析与配置管理。(Json比传统的XML作为配置文件使用,具备解析速度快,文件尺寸小等突出优点)


什么是Json

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、C++、C#、Java、JavaScript、Perl、Python等)。这些特性使JSON成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成(一般用于提升网络传输速率)。



JSON 语法 (JSON 语法是 JavaScript 对象表示语法的子集)

特点:

数据在键值对中,数据由逗号分隔。

花括号保存对象,方括号保存数组。

JSON 数据的书写格式是:名称/值对 "firstName":"John"

具体示例:




Json的解析方式:


目前(2017)国际国内对于Json 的解析主要有以下几种方式

.NET自带的运行时序列化和反序列化json工具。

命名空间 System.Runtime.Serialization.Json

缺点是需要编写大量代码,自己来封装一些实用方法,不推荐。

插件解析:

目前国内用的最多的Json解析插件: litejson

由于Unity公司也看到了Unity项目中对于大量Json 文件解析操作的需求,所以在Unity5.3以上版本开始原生提供Json的解析API,如下图:




对于Json 的初学者,为了更好的理解后面的配置管理技术讲解,特提供使用Unity的API 对Json 配置文件的解析示例:


Json基本解析示例

示例1:


对于Unity 原生支持Json 解析方法的最简测试演示。

namespaceTest{[Serializable]publicclassHero{//名称publicstringName;//等级publicLevelMyLevel;}}namespaceTest{[Serializable]publicclassLevel{publicintHeroLevel;}}


/*****Title:"SUIFW"UI框架项目*主题:演示Unity对Json解析APIusingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;namespaceTest{publicclassTestUnityJson:MonoBehaviour{voidStart(){HeroheroObj=newHero();heroObj.Name="郭靖";heroObj.MyLevel=newLevel(){HeroLevel=800};//相当于如下写法//Levellev=newLevel();//lev.HeroLevel=800;//heroObj.MyLevel=lev;//方法1:Json序列化工作(对象-->文件)stringstrHeroInfo=JsonUtility.ToJson(heroObj);Debug.Log("测试1:得到的序列化后的字符串="+strHeroInfo);//方法2:反序列化(Json文件-->对象)HeroheroInfo2=JsonUtility.FromJson<Hero>(strHeroInfo);Debug.Log("测试2:得到反序列化对象数值,名称:"+heroInfo2.Name+"等级:"+heroInfo2.MyLevel.HeroLevel);//方法3:测试覆盖反序列化。Herohero=newHero();hero.Name="杨过";hero.MyLevel=newLevel(){HeroLevel=500};//Json序列化stringheroInfo3=JsonUtility.ToJson(hero);//测试覆盖反序列化JsonUtility.FromJsonOverwrite(heroInfo3,heroObj);Debug.Log("测试3,得到再次反序列化覆盖的对象信息,名称:"+heroObj.Name+"等级:"+heroObj.MyLevel.HeroLevel);}}}



示例2:

对于Json 文件的实战性测试用例演示。

/*****Title:"SUIFW"UI框架项目*主题:对于Unity中Resource目录下的Json文件的解析Demo*Description:*功能:yyy**Date:2017*Version:0.1版本*ModifyRecoder:***/usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;namespaceTest{publicclassTestUnityJson2:MonoBehaviour{voidStart(){//提取文件,得到字符串数据TextAssetTaObj=Resources.Load<TextAsset>("People");//反序列化文件-->对象PersonInfoperInfo=JsonUtility.FromJson<PersonInfo>(TaObj.text);//显示对象中数据foreach(PeopleperinperInfo.People){Debug.Log("");Debug.Log(string.Format("name={0},Age={1}",per.Name,per.Age));}}}}



以上代码解释如下:


Unity(5.3以上版本)提供的JsonUtility 提供了三个重要方法


JsonUtility.ToJson() //表示进行序列化操作,把对象序列化为字符串。

JsonUtility.FromJson() ;//表示进行反序列化操作,把Json字符串反序列化为对象。

JsonUtility.FromJsonOverwrite();//是覆盖方式进行反序列化。



有了以上技术储备,我们就可以进行开发“通用配置管理器”了。


第1步: 首先定义通用配置管理器接口与辅助类。


代码如下:

/*****Title:"SUIFW"UI框架项目*主题:通用配置管理器接口*Description:*功能:*基于“键值对”配置文件的通用解析**Date:2017*Version:0.1版本*ModifyRecoder:***/usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;namespaceSUIFW{publicinterfaceIConfigManager{///<summary>///只读属性:应用设置///功能:得到键值对集合数据///</summary>Dictionary<string,string>AppSetting{get;}///<summary>///得到配置文件(AppSeting)最大的数量///</summary>///<returns></returns>intGetAppSettingMaxNumber();}[Serializable]internalclassKeyValuesInfo{//配置信息publicList<KeyValuesNode>ConfigInfo=null;}[Serializable]internalclassKeyValuesNode{//键publicstringKey=null;//值publicstringValue=null;}}



第2步: 定义Json 解析异常类。


Json 的解析过程如果出错,推荐使用我们自己定义的异常处理,为了更好的发现程序错误,所以自定义Json 解析异常类定义如下:


/*****Title:"SUIFW"UI框架项目*主题:Json解析异常*Description:*功能:专门负责对于JSon由于路径错误,或者Json格式错误造成的异常,进行捕获。**Date:2017*Version:0.1版本*ModifyRecoder:***/usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;namespaceSUIFW{publicclassJsonAnlysisException:Exception{publicJsonAnlysisException():base(){}publicJsonAnlysisException(stringexceptionMessage):base(exceptionMessage){}}}


第3步:定义“配置管理器”类


开发实现IConfigManager 接口的通用配置管理器


/*****Title:"SUIFW"UI框架项目*主题:基于Json配置文件的“配置管理器”*Description:*功能:**Date:2017*Version:0.1版本*ModifyRecoder:***/usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;namespaceSUIFW{publicclassConfigManagerByJson:IConfigManager{//保存(键值对)应用设置集合privatestaticDictionary<string,string>_AppSetting;///<summary>///只读属性:得到应用设置(键值对集合)///</summary>publicDictionary<string,string>AppSetting{get{return_AppSetting;}}///<summary>///构造函数///</summary>///<paramname="jsonPath">Json配置文件路径</param>publicConfigManagerByJson(stringjsonPath){_AppSetting=newDictionary<string,string>();//初始化解析Json数据,加载到(_AppSetting)集合。InitAndAnalysisJson(jsonPath);}///<summary>///得到AppSetting的最大数值///</summary>///<returns></returns>publicintGetAppSettingMaxNumber(){if(_AppSetting!=null&&_AppSetting.Count>=1){return_AppSetting.Count;}else{return0;}}///<summary>///初始化解析Json数据,加载到集合众。///</summary>///<paramname="jsonPath"></param>privatevoidInitAndAnalysisJson(stringjsonPath){TextAssetconfigInfo=null;KeyValuesInfokeyvalueInfoObj=null;//参数检查if(string.IsNullOrEmpty(jsonPath))return;//解析Json配置文件try{configInfo=Resources.Load<TextAsset>(jsonPath);keyvalueInfoObj=JsonUtility.FromJson<KeyValuesInfo>(configInfo.text);}catch{thrownewJsonAnlysisException(GetType()+"/InitAndAnalysisJson()/JsonAnalysisException!ParameterjsonPath="+jsonPath);}//数据加载到AppSetting集合中foreach(KeyValuesNodenodeInfoinkeyvalueInfoObj.ConfigInfo){_AppSetting.Add(nodeInfo.Key,nodeInfo.Value);}}}}


代码说明:

以上定义的“配置管理器”,可以对所有具备“键值对”特性的Json 配置文件,做统一数据提取工作,从而对于“UI预设”、“游戏对象”、“日志配置文件”、“语言国际化”等信息,可以做统一处理,极大提供开发效率。以下笔者提供本UI框架需要用到的除企业日志系统外,其他两种配置文件的截图,供参考。



(企业级Log日志中使用到的配置信息)



(“UI预设” 路径信息Json配置文件)

本篇就先写到这,下篇 "游戏UI框架设计(6)_消息传递中心" 继续。