Unity3d通用工具类之数据配置加载类
今天,我们来讲讲游戏中的数据配置加载。
什么是游戏数据加载呢?一般来说游戏中会有场景地图。
按照国际惯例,先贴一张游戏场景的地图:
在这张地图上,我们可以看到有很多正六边形,正六边形上有树木、岩石等。
哎!那么问题也就来了。大家会思考这张地图怎么啦。关游戏数据配置有什么关系?我们做好场景直接loding进来不就行了?
这也就是问题所在,如果你是直接loding进场景有很多问题:
1.场景是死的。只能是这个做好的场景。如果你想删除一些正六边形,想改变一些树木的位置,如何完成。有人会想,那我再做一个这样场景不就行了。ok,如果死策划想要另外,再另外外外。。。的场景,好了,你做到手抽筋都做不完。
如果是数据配置的话,我们只需要修改一些配置表上的一些数据就可以了,然后我们在程序里面动态的加载这个场景就行了。
2.不易游戏热更新。当我们想要改变游戏场景,我们只能重新下载做好的场景,然后替换掉游戏里面的文件。一个场景有多大,大家想想就知道了。
如果是数据配置的话,我们只需要更新xml的配置表就完全ok了。这两者的差别是一个天上一个地上的差别。
3.暂时想不出来。留给你们补充了。
ok,既然讲了数据配置这么多的好处。我们现在就来写写通用的数据配置加载。
按照国际惯例,在写之前我们需要设计这些类。
1.首先,要有数据管理类GameDataManager,管理这不同类型的数据,比如地图数据,tip提示字符串数据,特效数据等等
2.既然有管理类,肯定要有我们的GameData类。
先来看一张配置表的信息:
可以看到map有包括id,因为不止一张地图。埃!既然不止一张地图,所以我们就得用dictionary<int,>
一个map里面除了id之外还存放着许多不同类型变量的数值。所以我们需要类来存这些变量,也就是GameData,但是GameData只能是一个类型的。
比如你设计的GameData类里面有fog,fogColor这些字段来存储地图信息,但是这只能是地图,你特效这些数据怎么办,难道要创建一个特效EffectData。所以我们把GameData当成基类。
由于一个地图类,里面就分开好多不同的地图,所以我们用dictionary<int,T>泛型来存储,int=>id,T=>GameData
所以我们就需要设计一个泛型的GameData<T>类,而T是继承GameData<T>.可能有些乱,看看uml就清晰了一些:
using UnityEngine;
using System.Collections.Generic;
#region 模块信息
/*----------------------------------------------------------------
// 模块名:GameData
// 创建者:chen
// 修改者列表:
// 创建日期:2015.11.8
// 模块描述:数据配置类
//----------------------------------------------------------------*/
#endregion
public class GameData
{
public int id;
public static Dictionary<int,T> GetData<T>()
{
Dictionary<int, T> dataMap;
var type = typeof(T);
var fileNameField = type.GetField("fileName");//这里取得对应的xml文件名
if (fileNameField != null)
{
string filename = fileNameField.GetValue(null) as string;
dataMap = GameDataManager.Instance.FormatXMLData(filename, typeof(Dictionary<int, T>), type) as Dictionary<int, T>;
}
else
{
dataMap = new Dictionary<int, T>();
}
return dataMap;
}
}
public class GameData<T> : GameData where T : GameData<T>
{
private static Dictionary<int,T> m_data;
public static Dictionary<int,T> Data
{
get
{
if (null == m_data)
{
m_data = GetData<T>();
}
return m_data;
}
set
{
m_data = value;
}
}
}
GameDataManager:
using UnityEngine;
using System.Collections.Generic;
using System;
#region 模块信息
/*----------------------------------------------------------------
// 模块名:Gam
// 创建者:chen
// 修改者列表:
// 创建日期:#CREATIONDATE#
// 模块描述:数据加载类
//----------------------------------------------------------------*/
#endregion
public class GameDataManager
{
private static GameDataManager m_instance;
protected static readonly bool m_bIsPreloadData = true;
protected readonly string m_resourcePath = Application.dataPath+"/";
public static GameDataManager Instance
{
get
{
return m_instance ?? new GameDataManager();//??合并运算符,只当运算符的左操作数不为 null,此运算符将返回左操作数;否则返回右操作数
}
} public object FormatXMLData(string filename,Type dicType,Type type)
{
filename = string.Concat(this.m_resourcePath, filename, ".xml");
object result = null;
try
{
result = dicType.GetConstructor(Type.EmptyTypes).Invoke(null);
Dictionary<int, Dictionary<string, string>> map;
if (XMLParser.LoadIntoMap(filename, out map))//为何不让类的负担太重,这里我吧加载xml成dictionary单独分成一个类来处理
{
var props = type.GetProperties();//取得类的所有属性
foreach (var item in map)
{
var t = type.GetConstructor(Type.EmptyTypes).Invoke(null);
foreach (var prop in props)
{
if (prop.Name.Equals("id"))
{
prop.SetValue(t, item.Key, null);//如果是id的话,就设置属性值
}
else
{
if (item.Value.ContainsKey(prop.Name))
{
var value = UnityTools.GetValue(item.Value[prop.Name], prop.PropertyType);//通用工具类,吧string的格式转成对应的数据类型
prop.SetValue(t, value, null);
}
}
}
dicType.GetMethod("Add").Invoke(result, new object[] { item.Key, t });//result是dicType的实例,也就是dic<int,T>
//item.key=>id,t是泛型T的实例
}
}
}
catch (Exception e)
{
Debug.LogError(e.ToString());
}
return result;
} }
XMLParser:
using UnityEngine;
using System.Collections.Generic;
using System;
using System.Xml;
#region 模块信息
/*----------------------------------------------------------------
// 模块名:XMLParser
// 创建者:chen
// 修改者列表:
// 创建日期:#CREATIONDATE#
// 模块描述:
//----------------------------------------------------------------*/
#endregion
public class XMLParser
{
public static bool LoadIntoMap(string filename,out Dictionary<int,Dictionary<string,string>> map)
{
try
{
XmlDocument xml = new XmlDocument();
xml.Load(filename);
if (null == xml)
{
Debug.LogError("xml文件不存在" + filename);
map = null;
return false;
}
else
{
map = LoadIntoMap(xml, filename);
return true;
}
}
catch(Exception e)
{
Debug.LogError("XML加载出错:" + e.ToString());
map = null;
return false;
}
}
public static Dictionary<int, Dictionary<string, string>> LoadIntoMap(XmlDocument doc,string filePath)
{
Dictionary<int, Dictionary<string, string>> result = new Dictionary<int, Dictionary<string, string>>();
int index = 0;
XmlNode root = doc.SelectSingleNode("root");
foreach (XmlNode node in root.ChildNodes)//root的子节点,就拿map_setting来讲就是map子节点
{
index++;
if (null == node.ChildNodes || 0 == node.ChildNodes.Count)
{
Debug.LogWarning("The XML is empty nodes");
continue;
}
int key = int.Parse(node.ChildNodes[0].InnerText);//map[0] ==> id
if (result.ContainsKey(key))
{
Debug.LogWarning(string.Format("key:{0} is already loaded", key));
continue;
}
var children = new Dictionary<string, string>();
result.Add(key, children);
for (int i = 1; i < node.ChildNodes.Count; i++)//去除id,所以i从1开始(这样id节点得放在第一个位置)
{
var childNode = node.ChildNodes[i];
string tag;
if (childNode.Name.Length < 3)
{
tag = childNode.Name;
}
else
{
var tagTial = childNode.Name.Substring(childNode.Name.Length - 2, 2);//截取最后两个字符
if (tagTial == "_i" || tagTial == "_s" || tagTial == "_f" || tagTial == "_l" || tagTial == "k" || tagTial == "_m")
{
tag = childNode.Name.Substring(0, childNode.Name.Length - 2);
}
else
{
tag = childNode.Name;
}
}
if (childNode != null && !children.ContainsKey(tag))
{
if (string.IsNullOrEmpty(childNode.InnerText))
{
children.Add(tag, "");
}
else
{
children.Add(tag, childNode.InnerText.Trim());
}
}
else
{
Debug.LogWarning(string.Format("XML文件子节点的Key:{0} 已经存在",tag));
}
}
}
return result;
}
}
UnityTools:
/// <summary>
/// 将字符串转化成为对应类型的值
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object GetValue(string value, Type type)
{
if (null == type)
{
return null;
}
else if (type == typeof(int))
{
return Convert.ToInt32(value);
}
else if (type == typeof(float))
{
return float.Parse(value);
}
else if (type == typeof(byte))
{
return Convert.ToByte(value);
}
else if (type == typeof(double))
{
return Convert.ToDouble(value);
}
else if (type == typeof(bool))
{
if (value == "0")
{
return false;
}
else if (value == "1")
{
return true;
}
}
return null;
}
既然已经写好了,如何使用呢?很简单,我们只需一句代码:比如
GameData<MapData>.dataMap这样就行啦!!!!!
前提是写好MapData类。注意MapData里面都需要写的是属性。不是字段。
Unity3d通用工具类之数据配置加载类的更多相关文章
- Unity3d通用工具类之数据配置加载类-ini配置文件加载
Unity3d通用工具类之数据配置加载类-ini配置文件加载 上次我们讲过xml文件的加载配置管理,今天我们换个配置文件,也是比较常见的配置文件.ini格式的数据. 按照国际管理先贴一张啥是.ini文 ...
- 深入理解 Laravel 中 config 配置加载原理
Laravel的配置加载其实就是加载config目录下所有文件配置.如何过使用php artisan config:cache则会把加载的配置合并到一个配置文件中,下次请求就不会再去加载config目 ...
- Java运行时动态加载类之ClassLoader
https://blog.csdn.net/fjssharpsword/article/details/64922083 *************************************** ...
- Html飞机大战(四):状态的切换(界面加载类的编辑)
好家伙,接着写 既然我们涉及到状态了,那么我们也会涉及到状态的切换 那么我们怎样切换状态呢? 想象一下,如果我玩的游戏暂停了,那么我们肯定是通过点击或者按下某个按键来让游戏继续 这里我们选 ...
- 10月27日PHP加载类、设计模式(单例模式和工厂模式)、面向对象的六大原则
加载类可以使用include.require.require_once三种中的任意一种,每个关键字都有两种方法,但是这种方法的缺点是需要加载多少个php文件,就要写多少个加载类的方法.一般也就需要加载 ...
- [javaSE] 反射-动态加载类
Class.forName(“类的全称”) ①不仅表示了类的类类型,还代表了动态加载类 ②请大家区分编译,运行 ③编译时刻加载类是静态加载类,运行时刻加载类是动态加载类 Ⅰ所有的new对象都是静态加载 ...
- java动态加载类和静态加载类笔记
JAVA中的静态加载类是编译时刻加载类 动态加载类指的是运行时刻加载类 二者有什么区别呢 举一个例子 现在我创建了一个类 实现的功能假设为通过传入的参数调用具体的类和方法 class offic ...
- java反射动态加载类Class.forName();
1,所有的new出来的对象都是静态加载的,在程序编译的时候就会进行加载.而使用反射机制Class.forName是动态加载的,在运行时刻进行加载. 例子:直接上两个例子 public class Ca ...
- 反射01 Class类的使用、动态加载类、类类型说明、获取类的信息
0 Java反射机制 反射(Reflection)是 Java 的高级特性之一,是框架实现的基础. 0.1 定义 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对 ...
随机推荐
- CSS3中的矩阵
CSS3中的矩阵 CSS3中的矩阵指的是一个方法,书写为matrix()和matrix3d(),前者是元素2D平面的移动变换(transform),后者则是3D变换.2D变换矩阵为3*3,如下面矩阵示 ...
- BFC(块级格式化上下文)
渲染规则 1.内部的box会在垂直方向,一个接一个的放置 2.box垂直方向的距离由margin决定,属于同一个bfc的两个相邻box的margin会发生重叠 3.每个元素的margin box的左边 ...
- 什么是VC、PE、LP、GP?
天使基金主要关注原创项目构思和小型初创项目,投资规模大多在300万元以下:风险投资关注初创时期企业长期投资,规模在1000万元以下:私募股权投资主要关注3年内可以上市的成熟型企业. VC即ventur ...
- beego离线安装及运行
官网: https://beego.me/ 由于公司上不了网,啥都得下载到本地来弄. go的安装不多说了,GOPATH要设置好的. 先离线下载好https://github.com/astaxie/b ...
- loadrunner可用许可证
global-100: AEAMAUIK-YAFEKEKJJKEEA-BCJGIweb-10000: AEABEXFR-YTIEKEKJJMFKEKEKWBRAUNQJU-KBYGBglobal-10 ...
- LoadRunner监控Linux的三种方法
方法一.LR + SiteScope/nmon 方法二.使用rstatd包 1.下载rpc.rstatd-4.0.1.tar.gz 2.解压缩 tar -zxvf rpc.rstatd-4.0.1.t ...
- PHP 5.4 内置 web 服务器
之前 OSC 翻译了一篇文章:在 Windows 上使用 PHP 5.4 内置的 Web 服务器 下面这篇文章来自外刊IT评论翻译的在 Linux 下使用 PHP 5.4 内置 Web 服务器 PHP ...
- NOIP2013 D1 T2火柴排队
题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示 ...
- [I/O]javaI/O工作机制
摘要:IO问题可以说是当今web应用中面临的主要问题之一.因为在这个数据爆发的时代,海量的数据在网络到处流动,而在这个过程中都会涉及IO问题,可以说IO问题已经成为web应用的瓶颈之一.如何优化?以此 ...
- [BZOJ4651][NOI2016]网格(Tarjan)
下面直接给出结论,相关证明见官方题解. 1.若跳蚤数不超过1或仅有两只跳蚤且相邻,则答案为-1. 2.若跳蚤形成的连通块个数大于1,则答案为0. 3.若跳蚤之间建图存在割点,则答案为1. 4.否则为2 ...