今天,我们来讲讲游戏中的数据配置加载。

什么是游戏数据加载呢?一般来说游戏中会有场景地图。

按照国际惯例,先贴一张游戏场景的地图:

在这张地图上,我们可以看到有很多正六边形,正六边形上有树木、岩石等。

哎!那么问题也就来了。大家会思考这张地图怎么啦。关游戏数据配置有什么关系?我们做好场景直接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就清晰了一些:

  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. #region 模块信息
  4. /*----------------------------------------------------------------
  5. // 模块名:GameData
  6. // 创建者:chen
  7. // 修改者列表:
  8. // 创建日期:2015.11.8
  9. // 模块描述:数据配置类
  10. //----------------------------------------------------------------*/
  11. #endregion
  12. public class GameData
  13. {
  14. public int id;
  15. public static Dictionary<int,T> GetData<T>()
  16. {
  17. Dictionary<int, T> dataMap;
  18. var type = typeof(T);
  19. var fileNameField = type.GetField("fileName");//这里取得对应的xml文件名
  20. if (fileNameField != null)
  21. {
  22. string filename = fileNameField.GetValue(null) as string;
  23. dataMap = GameDataManager.Instance.FormatXMLData(filename, typeof(Dictionary<int, T>), type) as Dictionary<int, T>;
  24. }
  25. else
  26. {
  27. dataMap = new Dictionary<int, T>();
  28. }
  29. return dataMap;
  30. }
  31. }
  32. public class GameData<T> : GameData where T : GameData<T>
  33. {
  34. private static Dictionary<int,T> m_data;
  35. public static Dictionary<int,T> Data
  36. {
  37. get
  38. {
  39. if (null == m_data)
  40. {
  41. m_data = GetData<T>();
  42. }
  43. return m_data;
  44. }
  45. set
  46. {
  47. m_data = value;
  48. }
  49. }
  50. }

 GameDataManager:

  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using System;
  4. #region 模块信息
  5. /*----------------------------------------------------------------
  6. // 模块名:Gam
  7. // 创建者:chen
  8. // 修改者列表:
  9. // 创建日期:#CREATIONDATE#
  10. // 模块描述:数据加载类
  11. //----------------------------------------------------------------*/
  12. #endregion
  13. public class GameDataManager
  14. {
  15. private static GameDataManager m_instance;
  16. protected static readonly bool m_bIsPreloadData = true;
  17. protected readonly string m_resourcePath = Application.dataPath+"/";
  18. public static GameDataManager Instance
  19. {
  20. get
  21. {
  22. return m_instance ?? new GameDataManager();//??合并运算符,只当运算符的左操作数不为 null,此运算符将返回左操作数;否则返回右操作数
  23. }
  24. }
  25.  
  26. public object FormatXMLData(string filename,Type dicType,Type type)
  27. {
  28. filename = string.Concat(this.m_resourcePath, filename, ".xml");
  29. object result = null;
  30. try
  31. {
  32. result = dicType.GetConstructor(Type.EmptyTypes).Invoke(null);
  33. Dictionary<int, Dictionary<string, string>> map;
  34. if (XMLParser.LoadIntoMap(filename, out map))//为何不让类的负担太重,这里我吧加载xml成dictionary单独分成一个类来处理
  35. {
  36. var props = type.GetProperties();//取得类的所有属性
  37. foreach (var item in map)
  38. {
  39. var t = type.GetConstructor(Type.EmptyTypes).Invoke(null);
  40. foreach (var prop in props)
  41. {
  42. if (prop.Name.Equals("id"))
  43. {
  44. prop.SetValue(t, item.Key, null);//如果是id的话,就设置属性值
  45. }
  46. else
  47. {
  48. if (item.Value.ContainsKey(prop.Name))
  49. {
  50. var value = UnityTools.GetValue(item.Value[prop.Name], prop.PropertyType);//通用工具类,吧string的格式转成对应的数据类型
  51. prop.SetValue(t, value, null);
  52. }
  53. }
  54. }
  55. dicType.GetMethod("Add").Invoke(result, new object[] { item.Key, t });//result是dicType的实例,也就是dic<int,T>
  56. //item.key=>id,t是泛型T的实例
  57. }
  58. }
  59. }
  60. catch (Exception e)
  61. {
  62. Debug.LogError(e.ToString());
  63. }
  64. return result;
  65. }
  66.  
  67. }

XMLParser:

  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using System;
  4. using System.Xml;
  5. #region 模块信息
  6. /*----------------------------------------------------------------
  7. // 模块名:XMLParser
  8. // 创建者:chen
  9. // 修改者列表:
  10. // 创建日期:#CREATIONDATE#
  11. // 模块描述:
  12. //----------------------------------------------------------------*/
  13. #endregion
  14. public class XMLParser
  15. {
  16. public static bool LoadIntoMap(string filename,out Dictionary<int,Dictionary<string,string>> map)
  17. {
  18. try
  19. {
  20. XmlDocument xml = new XmlDocument();
  21. xml.Load(filename);
  22. if (null == xml)
  23. {
  24. Debug.LogError("xml文件不存在" + filename);
  25. map = null;
  26. return false;
  27. }
  28. else
  29. {
  30. map = LoadIntoMap(xml, filename);
  31. return true;
  32. }
  33. }
  34. catch(Exception e)
  35. {
  36. Debug.LogError("XML加载出错:" + e.ToString());
  37. map = null;
  38. return false;
  39. }
  40. }
  41. public static Dictionary<int, Dictionary<string, string>> LoadIntoMap(XmlDocument doc,string filePath)
  42. {
  43. Dictionary<int, Dictionary<string, string>> result = new Dictionary<int, Dictionary<string, string>>();
  44. int index = 0;
  45. XmlNode root = doc.SelectSingleNode("root");
  46. foreach (XmlNode node in root.ChildNodes)//root的子节点,就拿map_setting来讲就是map子节点
  47. {
  48. index++;
  49. if (null == node.ChildNodes || 0 == node.ChildNodes.Count)
  50. {
  51. Debug.LogWarning("The XML is empty nodes");
  52. continue;
  53. }
  54. int key = int.Parse(node.ChildNodes[0].InnerText);//map[0] ==> id
  55. if (result.ContainsKey(key))
  56. {
  57. Debug.LogWarning(string.Format("key:{0} is already loaded", key));
  58. continue;
  59. }
  60. var children = new Dictionary<string, string>();
  61. result.Add(key, children);
  62. for (int i = 1; i < node.ChildNodes.Count; i++)//去除id,所以i从1开始(这样id节点得放在第一个位置)
  63. {
  64. var childNode = node.ChildNodes[i];
  65. string tag;
  66. if (childNode.Name.Length < 3)
  67. {
  68. tag = childNode.Name;
  69. }
  70. else
  71. {
  72. var tagTial = childNode.Name.Substring(childNode.Name.Length - 2, 2);//截取最后两个字符
  73. if (tagTial == "_i" || tagTial == "_s" || tagTial == "_f" || tagTial == "_l" || tagTial == "k" || tagTial == "_m")
  74. {
  75. tag = childNode.Name.Substring(0, childNode.Name.Length - 2);
  76. }
  77. else
  78. {
  79. tag = childNode.Name;
  80. }
  81. }
  82. if (childNode != null && !children.ContainsKey(tag))
  83. {
  84. if (string.IsNullOrEmpty(childNode.InnerText))
  85. {
  86. children.Add(tag, "");
  87. }
  88. else
  89. {
  90. children.Add(tag, childNode.InnerText.Trim());
  91. }
  92. }
  93. else
  94. {
  95. Debug.LogWarning(string.Format("XML文件子节点的Key:{0} 已经存在",tag));
  96. }
  97. }
  98. }
  99. return result;
  100. }
  101. }
  1. UnityTools:
  1. /// <summary>
  2. /// 将字符串转化成为对应类型的值
  3. /// </summary>
  4. /// <param name="value"></param>
  5. /// <param name="type"></param>
  6. /// <returns></returns>
  7. public static object GetValue(string value, Type type)
  8. {
  9. if (null == type)
  10. {
  11. return null;
  12. }
  13. else if (type == typeof(int))
  14. {
  15. return Convert.ToInt32(value);
  16. }
  17. else if (type == typeof(float))
  18. {
  19. return float.Parse(value);
  20. }
  21. else if (type == typeof(byte))
  22. {
  23. return Convert.ToByte(value);
  24. }
  25. else if (type == typeof(double))
  26. {
  27. return Convert.ToDouble(value);
  28. }
  29. else if (type == typeof(bool))
  30. {
  31. if (value == "0")
  32. {
  33. return false;
  34. }
  35. else if (value == "1")
  36. {
  37. return true;
  38. }
  39. }
  40. return null;
  41. }

既然已经写好了,如何使用呢?很简单,我们只需一句代码:比如

GameData<MapData>.dataMap这样就行啦!!!!!

前提是写好MapData类。注意MapData里面都需要写的是属性。不是字段。

Unity3d通用工具类之数据配置加载类的更多相关文章

  1. Unity3d通用工具类之数据配置加载类-ini配置文件加载

    Unity3d通用工具类之数据配置加载类-ini配置文件加载 上次我们讲过xml文件的加载配置管理,今天我们换个配置文件,也是比较常见的配置文件.ini格式的数据. 按照国际管理先贴一张啥是.ini文 ...

  2. 深入理解 Laravel 中 config 配置加载原理

    Laravel的配置加载其实就是加载config目录下所有文件配置.如何过使用php artisan config:cache则会把加载的配置合并到一个配置文件中,下次请求就不会再去加载config目 ...

  3. Java运行时动态加载类之ClassLoader

    https://blog.csdn.net/fjssharpsword/article/details/64922083 *************************************** ...

  4. Html飞机大战(四):状态的切换(界面加载类的编辑)

    好家伙,接着写   既然我们涉及到状态了,那么我们也会涉及到状态的切换   那么我们怎样切换状态呢? 想象一下,如果我玩的游戏暂停了,那么我们肯定是通过点击或者按下某个按键来让游戏继续   这里我们选 ...

  5. 10月27日PHP加载类、设计模式(单例模式和工厂模式)、面向对象的六大原则

    加载类可以使用include.require.require_once三种中的任意一种,每个关键字都有两种方法,但是这种方法的缺点是需要加载多少个php文件,就要写多少个加载类的方法.一般也就需要加载 ...

  6. [javaSE] 反射-动态加载类

    Class.forName(“类的全称”) ①不仅表示了类的类类型,还代表了动态加载类 ②请大家区分编译,运行 ③编译时刻加载类是静态加载类,运行时刻加载类是动态加载类 Ⅰ所有的new对象都是静态加载 ...

  7. java动态加载类和静态加载类笔记

    JAVA中的静态加载类是编译时刻加载类  动态加载类指的是运行时刻加载类 二者有什么区别呢 举一个例子  现在我创建了一个类  实现的功能假设为通过传入的参数调用具体的类和方法 class offic ...

  8. java反射动态加载类Class.forName();

    1,所有的new出来的对象都是静态加载的,在程序编译的时候就会进行加载.而使用反射机制Class.forName是动态加载的,在运行时刻进行加载. 例子:直接上两个例子 public class Ca ...

  9. 反射01 Class类的使用、动态加载类、类类型说明、获取类的信息

    0 Java反射机制 反射(Reflection)是 Java 的高级特性之一,是框架实现的基础. 0.1 定义 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对 ...

随机推荐

  1. fastdfs5.11+centos7.2 按照部署(一)【转载】

    1.绪论 最近要用到fastDFS,所以自己研究了一下,在搭建FastDFS的过程中遇到过很多的问题,为了能帮忙到以后搭建FastDFS的同学,少走弯路,与大家分享一下.FastDFS的作者淘宝资深架 ...

  2. AC日记——830A - Office Keys

    思路: 背包: 代码: #include <cmath> #include <cstdio> #include <cstring> #include <ios ...

  3. email 校验

    email 校验: javascript: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/ java: ^([a- ...

  4. SQL Join简单介绍

    前沿 Join是关系型数据库系统的重要操作之一,SQL Server中包含的常用Join:内联接.外联接和交叉联接等. 如果我们想在两个或以上的表获取其中从一个表中的行与另一个表中的行匹配的数据,这时 ...

  5. matlab下mex 调用opencv库

    1. 首先写好待编译的.cpp文件,使用混合编程,以人脸检测为例 #include "mex.h" // Required for the use of MEX files // ...

  6. mysql-8.0.12安装和配置

    1.下载Mysql8.0.12压缩包.下载地址:https://dev.mysql.com/downloads/file/?id=480557 2.解压文件到本地指定目录.这里我的mysql根目录是: ...

  7. Codeforces 493 E.Devu and Birthday Celebration

    \(>Codeforces \space 493\ E.Devu\ and\ Birthday\ Celebration<\) 题目大意 : 有 \(q\) 组询问,每次有 \(n\) 小 ...

  8. 【lct】poj2763 Housewife Wind

    题意:给你一棵树,边带权,支持两种操作:修改某条边的权值:查询两点之间的最短路. lct主要实现单点修改和路径和. 修改x结点的值只需将x Splay到其所在辅助树的根,然后修改其值,再maintai ...

  9. 尝试用Gearman实现分布式处理(PHP)[转]

    本文需要你已对Gearman有个大致了解. 顺便再推荐两篇参考文章http://hi.baidu.com/thinkinginlamp/blog/item/ff49972b9e7378f3e6cd40 ...

  10. python爬取基础网页图片

    python基础爬虫总结 1.爬取信息原理 与浏览器客户端类似,向网站的服务器发送一个请求,该请求一般是url,也就是网址.之后服务器响应一个html页面给客户端,当然也有其他数据类型的信息,这些就是 ...