说明:写了一个通用的txt解析类,通过获取对象属性的名字使用txt数据自动初始化对象。
直接看获取数据的代码调用:
public class TestTxtDataAnalysis : MonoBehaviour {
void Start () {
// 遍历道具和武器数据集合,输出ID和名字
for (int i = 1; i <= PropAndWeaponData.DicData.Count; i++)
{
Debug.Log("ID:" + PropAndWeaponData.DicData[i].Id + " 名字:" + PropAndWeaponData.DicData[i].Name);
}
}
}
结果(只截部分):
然后再来看具体实现:
一、txt文件的配置
1、用CSV格式文件配置好数据。
2、将CSV另存为txt文件,或者直接复制一份,修改为txt格式。修改编码格式为utf-8无bom。
txt文件内容如下:
Id,Name,Desc,Type,Icon,Mod,Atk,AtkSpeed,CostMp,MaxAtkRange,AtkOffset,MaxThroughTargetNum,HitBackDis,BulletSpeed,CanBoom,BoomRange,BulletEffect,ExtraEffectId
1,基因点,货币,3,icon,Mod,0,0,0,0,0,0,0,0,0,0,0,0
2,蓝瓶,恢复药品,4,icon,Mod,0,0,0,0,0,0,0,0,0,0,0,0
3,红瓶,恢复药品,4,icon,Mod,0,0,0,0,0,0,0,0,0,0,0,0
4,单手枪,单手枪,11,icon,Mod,3,0.5,5,5,5,5,5,5,1,5,5,5
5,双手枪,双手枪,12,icon,Mod,3,0.5,5,5,5,5,5,5,1,5,5,5
6,刺枪,刺枪,13,icon,Mod,3,0.5,5,5,5,5,5,5,1,5,5,5
7,单手剑,单手剑,14,icon,Mod,3,0.5,1,2,3,4,5,6,1,2,3,4
二、PropAndWeaponData类
注意:自定义属性的名字必须和txt配置文件一致。
// 道具和武器数据表
public class PropAndWeaponData : TxtDataBase<PropAndWeaponData>
{
public const string DATA_PATH = "Data/ConfigData_PropAndWeapon"; // txt数据文件路径
// 自定义属性。注意:属性名字必须和txt数据文件的第一行的属性名完全一致
public int Id{ set; get; }
public string Name{ set; get; } // 名字
public string Desc{ set; get; } // 描述
//public PropAndWeaponType Type{ set; get; } // 类型
public int Type { set; get; } // 类型
public string Icon{ set; get; } //
public string Mod{ set; get; } //
// 武器属性
public int Atk{ set; get; } // 攻击力
public float AtkSpeed{ set; get; } // 攻速
public float CostMp{ set; get; } // 耗蓝
public float MaxAtkRange{ set; get; } // 最大射程
public float AtkOffset{ set; get; } // 攻击的子弹偏移
public int MaxThroughTargetNum{ set; get; } // 子弹最大击穿目标数
public float HitBackDis{ set; get; } // 击退距离
public float BulletSpeed{ set; get; } // 子弹速度
public float CanBoom{ set; get; } // 能否爆炸,1是,0否
public float BoomRange{ set; get; } // 爆炸范围
public string BulletEffect{ set; get; } // 子弹特效
public int ExtraEffectId{ set; get; } // 附加特效ID
#region 道具和武器类型
public enum PropAndWeaponType {
Coin = 3, // 货币
RecoveryProducts = 4, // 恢复用品
SingleGun = 11, // 单手枪
TwoHandGun = 12, // 双手枪
StabGun = 11, // 刺枪
OneHandSword = 12, // 单手剑
}
#endregion
}
三、txt解析类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq.Expressions;
using System.Text; // stringBuilding 需要
using System.Reflection; // 反射
public class TxtDataBase<T> where T: TxtDataBase<T>, new()
{
private static Dictionary<int, T> dicData = null; // 储存数据集合
// 初始化
private static void Init()
{
dicData = new Dictionary<int, T>(); // 初始化集合
AnalysisTxtToDic(); // 解析数据表txt数据到集合中
}
// 储存数据集合
public static Dictionary<int, T> DicData
{
get
{
if(dicData == null)
{
Init(); // 初始化
}
return dicData;
}
}
/// <summary>
/// 解析数据表txt数据到集合中
/// </summary>
private static void AnalysisTxtToDic()
{
// 根据属性名字获取数据文件路径的值
Type type = typeof(T);
FieldInfo fileNameField = type.GetField("DATA_PATH");
if (fileNameField == null)
return;
string strDataPath = fileNameField.GetValue(null) as string;
if (string.IsNullOrEmpty(strDataPath))
return;
//读取txt文件,有中文时,txt文件必须为utf-8无bom格式
TextAsset binAsset = Resources.Load(strDataPath, typeof(TextAsset)) as TextAsset;
if(binAsset == null)
{
Debug.LogError("txt文件为空,请检查。 文件路径:" + strDataPath);
return;
}
//读取每一行的内容
string[] lineArray = binAsset.text.Split('\n');
for (int i = 0; i < lineArray.Length; i++)
{
// 所有行,去掉末尾的换行符,前面已经去掉'\n'了,这里再去掉\r就行了
lineArray[i] = lineArray[i].TrimEnd((char[])"\r".ToCharArray());
}
string strFirstLine = lineArray[1];
string[] arrayPoperty = strFirstLine.Split(','); // 用于储存首行的拆分的所有属性
string[] tempArray; // 用于储存一行拆分的所有数据
// 将每行拆分的数据赋值给对应对象的参数
for (int i = 0; i < lineArray.Length; i++)
{
if (i == 0)
continue;
if (string.IsNullOrEmpty(lineArray[i])) // 最后一行可能为空
{
break;
}
tempArray = lineArray[i].Split(','); // 根据逗号分隔内容
// 输出拆分数据
//foreach (var item in tempArray)
//{
// Debug.Log("item=" + item);
//}
InitDataInDic_ByName(arrayPoperty, tempArray); // 将每行拆分的数据赋值给对应对象的参数(通过获取变量的名字自动匹配),并存储到集合中
}
}
/// <summary>
/// 将每行拆分的数据赋值给对应对象的参数(通过获取对象属性的名字自动匹配),并存储到集合中
/// 注意:对象属性的名字必须和配置文件中第一行的属性名字完全一致。
/// </summary>
/// <param name="arrayProperty">属性数组</param>
/// <param name="arrayValue">值数组</param>
private static void InitDataInDic_ByName(string[] arrayProperty, string[] arrayValue)
{
//Debug.Log(GetType() + "/InitPropAndWeaponDataInDic_ByName");
T propData = new T();
string[] strTempArray;
Vector3 vector3Temp;
foreach (System.Reflection.PropertyInfo p in propData.GetType().GetProperties()) // 遍历自定义对象的属性(注意:不能遍历字段和方法)
{
System.Reflection.PropertyInfo setobj = propData.GetType().GetProperty(p.Name); //搜索具有指定属性名称的公共属性
//Debug.Log("Name:= " + p.Name + " Value: =" + p.GetValue(s, null));
//Debug.Log("setobj=" + setobj);
//Debug.Log("setobj=" + setobj.PropertyType); //
for (int i = 0; i < arrayProperty.Length; i++) // 遍历解析的属性数组
{
if (arrayProperty[i].Equals(p.Name)) // 当属性数组里的属性类型 和 公共属性一致,则对公共属性进行赋值(先根据数据类型进行转换)
{
if (arrayValue[i] != null && setobj != null)
{
if (setobj.PropertyType.Equals(typeof(string))) // 判断公共属性的数据类型
{
setobj.SetValue(propData, arrayValue[i], null);
}
else if (setobj.PropertyType.Equals(typeof(int)))
{
setobj.SetValue(propData, Convert.ToInt32(arrayValue[i]), null);
}
else if (setobj.PropertyType.Equals(typeof(float)))
{
setobj.SetValue(propData, float.Parse(arrayValue[i]), null);
}
else if (setobj.PropertyType.Equals(typeof(bool))) // 布尔值,配置表为1表示true,为0表示为false
{
if(Convert.ToInt32(arrayValue[i]) == 1)
setobj.SetValue(propData, true, null);
else
setobj.SetValue(propData, false, null);
}
else if (setobj.PropertyType.Equals(typeof(int[]))) // 整形数组
{
if (arrayValue[i].Contains("|"))
{
strTempArray = arrayValue[i].Split('|'); // 整形数组以'|'分隔
int[] tempArray = new int[strTempArray.Length];
for (int m = 0; m < strTempArray.Length; m++)
{
tempArray[m] = Convert.ToInt32(strTempArray[m]);
}
setobj.SetValue(propData, tempArray, null);
}
else
{
int[] tempArray = { Convert.ToInt32(arrayValue[i])};
setobj.SetValue(propData, tempArray, null);
}
}
else if (setobj.PropertyType.Equals(typeof(Vector3))) // Vector3
{
if (arrayValue[i].Contains("|"))
{
strTempArray = arrayValue[i].Split('|'); // Vector3以'|'分隔
vector3Temp.x = float.Parse(strTempArray[0]);
vector3Temp.y = float.Parse(strTempArray[1]);
vector3Temp.z = float.Parse(strTempArray[2]);
setobj.SetValue(propData, vector3Temp, null);
}
else
{
Debug.LogError("InitDataInDic_ByName/" + "Vector3类型数据错误");
}
}
}
//Debug.Log("Name = " + p.Name + " Value =" + p.GetValue(propData, null));
break;
}
}
}
dicData.Add(Convert.ToInt32(arrayValue[0]), propData); // 添加到集合中
// 打日志,展示解析后的数据
DisplayAnalysisData(propData); // 测试数据读取是否正确,可以打开这行注释
}
/// <summary>
/// 展示解析后的数据
/// </summary>
private static void DisplayAnalysisData(T tObject)
{
//Debug.Log("TxtDataBase/DisplayTxtData");
foreach (System.Reflection.PropertyInfo p in tObject.GetType().GetProperties()) // 遍历自定义对象的属性(注意:不能遍历字段和方法)
{
System.Reflection.PropertyInfo setobj = tObject.GetType().GetProperty(p.Name); //搜索具有指定属性名称的公共属性
Debug.Log("Name:= " + p.Name + " Value: =" + p.GetValue(tObject, null));
//Debug.Log("setobj=" + setobj);
//Debug.Log("setobj=" + setobj.PropertyType); //
}
}
}