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里面都需要寫的是屬性。不是字段。





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM