游戏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 解析方法的最简测试演示。

 namespace Test
{
[Serializable]
public class Hero
{
//名称
public string Name;
//等级
public Level MyLevel; }
} namespace Test
{
[Serializable]
public class Level
{
public int HeroLevel; }
}
 /***
*
* Title: "SUIFW" UI框架项目
* 主题: 演示Unity 对Json 解析API using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace Test
{
public class TestUnityJson : MonoBehaviour { void Start () {
Hero heroObj=new Hero();
heroObj.Name = "郭靖";
heroObj.MyLevel = new Level() {HeroLevel = 800};
//相当于如下写法
//Level lev=new Level();
//lev.HeroLevel = 800;
//heroObj.MyLevel = lev; //方法1: Json 序列化工作(对象--> 文件)
string strHeroInfo = JsonUtility.ToJson(heroObj);
Debug.Log("测试1: 得到的序列化后的字符串="+strHeroInfo); //方法2: 反序列化(Json文件--> 对象)
Hero heroInfo2 = JsonUtility.FromJson<Hero>(strHeroInfo);
Debug.Log("测试2:得到反序列化对象数值,名称: "+heroInfo2.Name+" 等级: "+heroInfo2.MyLevel.HeroLevel); //方法3: 测试覆盖反序列化。
Hero hero=new Hero();
hero.Name = "杨过";
hero.MyLevel = new Level() {HeroLevel = 500}; //Json 序列化
string heroInfo3 = 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版本
* Modify Recoder:
*
*
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace Test
{
public class TestUnityJson2 : MonoBehaviour { void Start ()
{
//提取文件,得到字符串数据
TextAsset TaObj=Resources.Load<TextAsset>("People");
//反序列化 文件-->对象
PersonInfo perInfo=JsonUtility.FromJson<PersonInfo>(TaObj.text);
//显示对象中数据
foreach (People per in perInfo.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版本
* Modify Recoder:
*
*
*/ using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace SUIFW
{
public interface IConfigManager { /// <summary>
/// 只读属性: 应用设置
/// 功能: 得到键值对集合数据
/// </summary>
Dictionary<string, string> AppSetting { get; } /// <summary>
/// 得到配置文件(AppSeting)最大的数量
/// </summary>
/// <returns></returns>
int GetAppSettingMaxNumber(); } [Serializable]
internal class KeyValuesInfo
{
//配置信息
public List<KeyValuesNode> ConfigInfo = null;
} [Serializable]
internal class KeyValuesNode
{
//键
public string Key = null;
//值
public string Value = null;
}
}

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

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

 /***
*
* Title: "SUIFW" UI框架项目
* 主题: Json 解析异常
* Description:
* 功能:专门负责对于JSon 由于路径错误,或者Json 格式错误造成的异常,进行捕获。
*
* Date: 2017
* Version: 0.1版本
* Modify Recoder:
*
*
*/ using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace SUIFW
{
public class JsonAnlysisException : Exception {
public JsonAnlysisException() : base(){}
public JsonAnlysisException(string exceptionMessage) : base(exceptionMessage){}
}
}

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

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

 /***
*
* Title: "SUIFW" UI框架项目
* 主题:基于Json 配置文件的“配置管理器”
* Description:
* 功能:
*
* Date: 2017
* Version: 0.1版本
* Modify Recoder:
*
*
*/ using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace SUIFW
{
public class ConfigManagerByJson : IConfigManager
{
//保存(键值对)应用设置集合
private static Dictionary<string, string> _AppSetting; /// <summary>
/// 只读属性: 得到应用设置(键值对集合)
/// </summary>
public Dictionary<string, string> AppSetting
{
get { return _AppSetting; }
} /// <summary>
/// 构造函数
/// </summary>
/// <param name="jsonPath">Json配置文件路径</param>
public ConfigManagerByJson(string jsonPath)
{
_AppSetting=new Dictionary<string, string>();
//初始化解析Json 数据,加载到(_AppSetting)集合。
InitAndAnalysisJson(jsonPath);
} /// <summary>
/// 得到AppSetting 的最大数值
/// </summary>
/// <returns></returns>
public int GetAppSettingMaxNumber()
{
if (_AppSetting!=null && _AppSetting.Count>=)
{
return _AppSetting.Count;
}
else
{
return ;
}
} /// <summary>
/// 初始化解析Json 数据,加载到集合众。
/// </summary>
/// <param name="jsonPath"></param>
private void InitAndAnalysisJson(string jsonPath)
{
TextAsset configInfo = null;
KeyValuesInfo keyvalueInfoObj = null; //参数检查
if (string.IsNullOrEmpty(jsonPath)) return;
//解析Json 配置文件
try{
configInfo = Resources.Load<TextAsset>(jsonPath);
keyvalueInfoObj=JsonUtility.FromJson<KeyValuesInfo>(configInfo.text);
}
catch{
throw new JsonAnlysisException(GetType() + "/InitAndAnalysisJson()/Json Analysis Exception ! Parameter jsonPath=" + jsonPath);
}
//数据加载到AppSetting 集合中
foreach (KeyValuesNode nodeInfo in keyvalueInfoObj.ConfigInfo)
{
_AppSetting.Add(nodeInfo.Key,nodeInfo.Value);
}
} }
}

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

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

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

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

游戏UI框架设计(五): 配置管理与应用的更多相关文章

  1. 游戏UI框架设计(7): 资源国际化技术

    游戏UI框架设计(7) --资源国际化技术 说起"资源国际化"技术,个人认为可以追述到微软Window2000 PC操作系统的发布,在这之前windows98操作系统的开发都是先由 ...

  2. 游戏UI框架设计(四) : 模态窗体管理

    游戏UI框架设计(四) --模态窗体管理 我们在开发UI窗体时,对于"弹出窗体"往往因为需要玩家优先处理弹出小窗体,则要求玩家不能(无法)点击"父窗体",这种窗 ...

  3. 游戏UI框架设计(一) : 架构设计理论篇

    游戏UI框架设计(一) ---架构设计理论篇 前几天(2017年2月)看到一篇文章,国内王健林.马云等大咖们看好的未来十大最有"钱途"产业中,排名第一的就是"泛娱乐&qu ...

  4. 游戏UI框架设计(二) : 最简版本设计

    游戏UI框架设计(二) --最简版本设计 为降低难度决定先讲解一个最简版本,阐述UI框架的核心设计理念.这里先定义三个核心功能: 1:UI窗体的自动加载功能. 2:缓存UI窗体. 3:窗体生命周期(状 ...

  5. 游戏UI框架设计(三) : 窗体的层级管理

    游戏UI框架设计(三) ---窗体的层级管理 UI框架中UI窗体的"层级管理",最核心的问题是如何进行窗体的显示管理.窗体(预设)的显示我们前面定义了三种类型: 普通.隐藏其他.反 ...

  6. 游戏UI框架设计(6): 消息传递中心

    游戏UI框架设计(6) --消息传递中心 最近一直忙于一个益智类游戏的研发工作,所以博客有段时间没有更新了.经过朋友的督促,决定这两天立刻完成最后的两篇博客讲解(UI框架).说起“消息传递中心”,或者 ...

  7. 《开源框架那些事儿22》:UI框架设计实战

    UI是User Interface的缩写.通常被觉得是MVC中View的部分,作用是提供跟人机交互的可视化操作界面. MVC中Model提供内容给UI进行渲染,用户通过UI框架产生响应,一般而言会由控 ...

  8. 自己动手设计并实现一个linux嵌入式UI框架(设计)

    看了"自己动手设计并实现一个linux嵌入式UI框架"显然没有尽兴,因为还没有看到庐山真面目,那我今天继续,先来说说,我用到了哪些知识背景.如:C语言基础知识,尤其是指针.函数指针 ...

  9. WisDom.Net 框架设计(五) 权限设计

    WisDom.Net --权限设计 1.需求分析     基本在所有的管理系统中都离不开权限管理.可以这么说,权限管理是管理系统的核心所在. 权限管理说白一些就是每个人能够做什么,不能够做什么.可以说 ...

随机推荐

  1. Java多机部署下的定时任务处理方案(mysql)

    因为自己有csdn和博客园两个博客, 所以两边都会发一下. csdn地址: http://blog.csdn.net/u012881584/article/details/70194237 今天来说一 ...

  2. MySQL之字符集-校对规则

    一.字符集(Character set) 是多个字符(英文字符,汉字字符,或者其他国家语言字符)的集合,字符集种类较多,每个字符集包含的字符个数不同. 特点: ①字符编码方式是用一个或多个字节表示字符 ...

  3. XStream的使用

    一:功能 可以将JavaBean转换(序列化)成XMl 二:依赖jar包 xstream.jar xpp3_min.jar(xml pull parser)xml解析器 三:使用步骤 XStream ...

  4. 通过chrome inspect 来调试手机hybird APP

    hybird APP 虽然显示效果和编译前的前端页面大致相同,但是其中操作可能会调用一些浏览器中没有的接口,从而产生一些意料之外的问题,因此了解和掌握如何调试就变得尤为重要. 本文简要介绍了如何利用c ...

  5. 尚学堂Java第一课

    今天是北京尚学堂郑州分校开课的第一天,小班面授教学. 我很兴奋,是一个小白对IT大神渴求传道授业解惑的兴奋. 杨老师还是一贯耐心详细的手敲了第一堂课的完整大纲,必须给杨老师赞赞赞!!! 从幽默的制定班 ...

  6. 频繁模式挖掘中Apriori、FP-Growth和Eclat算法的实现和对比

    最近上数据挖掘的课程,其中学习到了频繁模式挖掘这一章,这章介绍了三种算法,Apriori.FP-Growth和Eclat算法:由于对于不同的数据来说,这三种算法的表现不同,所以我们本次就对这三种算法在 ...

  7. [uva11992]Fast Matrix Operations(多延迟标记,二维线段树,区间更新)

    题目链接:https://vjudge.net/problem/UVA-11992 题意:n*m的矩阵,每次对一个子矩阵操作,有三种操作:加x,设置为x,查询.查询返回子矩阵和.最小值.最大值 n很小 ...

  8. 如何使用python生成xml

    最近要用python生成一个xml格式的文件.因为有一些内容是中文,原来的xml文件中使用了CDATA 的部分. 而之前的python程序所用的库中没有 创建这个区域的方法.无奈研究了大半天. 最后用 ...

  9. 腾讯QQAndroid API调用实例(QQ分享无需登录)

    腾讯QQAndroid API调用实例(QQ分享无需登录)   主要分为两个步骤: 配置Androidmanifest.xml 修改activity里边代码 具体修改如下:   1.Activity代 ...

  10. UIView的属性

    .alpha 设置视图的透明度.默认为1. // 完全透明 view.alpha = ; // 不透明 view.alpha = ; .clipsToBounds // 默认是NO,当设置为yes时, ...