zoukankan      html  css  js  c++  java
  • 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里面都需要写的是属性。不是字段。




  • 相关阅读:
    值类型、引用类型作为方法参数如何执行,ref与out的区别
    asp.net 常用 验证正则表达式
    ASP.NET的错误处理机制
    MSSQL与MYSQL区别
    http协议状态码对照表
    EF 跨数据库支持
    请求管道中的19个事件
    一位软件工程师的6年总结本人读了深受启发,献给所有从事IT开发的人 [转载]
    Windows 窗体的.Net 框架绘图技术
    Windows Live Messenger 8.5 去广告方法及资源文件
  • 原文地址:https://www.cnblogs.com/CaomaoUnity3d/p/4947516.html
Copyright © 2011-2022 走看看