C# Unity游戏开发——Excel中的数据是如何到游戏中的 (二)
本帖是延续的:C# Unity游戏开发——Excel中的数据是如何到游戏中的 (一)
上个帖子主要是讲了如何读取Excel,本帖主要是讲述读取的Excel数据是如何序列化成二进制的,考虑到现在在手游中应用很广泛的序列化技术Google的ProtoBuf,所以本文也是按照ProtoBuf的方式来操作的。ProtoBuf是一个开源库,简单来说ProtoBuf就是一个能使序列化的数据变得更小的类库,当然这里指的更小是相对的。好了ProtBuf的东西就不在多说,以后会专门写一篇帖子的。本帖其实就相当于上帖中列出的“流程”中的2.将读取的数据进行序列化并写入文件。虽然这句话只有16个字,但是他的内容绝对不止16个字这么简单。
一开始计划的是这样的:1.先把Excel数据读出来。2.然后根据数据生成相应的类代码。3.然后再生成代码的实例并且通过反射(Reflection)把Excel中的数据填进去。4.最后用ProtBuf进行序列化。这听起来似乎很合理,不过在实现过程中还是遇到了几个棘手的问题。但是最重要的一个问题是,3.生成代码的实例并且通过反射(Reflection)把Excel中的数据填进去,中“生成实例”的过程。
在运行时生成的代码知识一串字符而已,想要生成字符串中的类的实例需要用到动态编译把代码编译后生成一个Assembly,然后用Assembly中的CreateInstance方法创建一个object类型的实例,这个实例就是字符串代码中的类的实例。但是,我们使用了ProtoBuf数据的格式来生成代码,所以工程中直接把ProtBuf的源码放进来而不是引入protobuf-net.dll,所以在动态编译设置编译参数来动态引入DLL文件的时候经常出错而导致,编译生成的Assembly是null。所以考虑到这些本文使用了一种折中的方案来跳过动态编译这个过程。
因为在Unity项目中我们关注的只是最终生成的二进制文件本身所以对于它是如何生成的对于Unity项目来说是没有任何影响的,只要保证数据的格式和生成代码的格式相对应一切就OK。基于此,我们把这个过程分成了两部分,1.生成代码。2.生成二进制文件(其实就是把编译的工作交给了编译器。。。)OK,话不多说了,帖代码吧!
1.生成代码
public static void GenerateCode()
{
FileInfo info;
FileStream stream;
IExcelDataReader excelReader;
DataSet result;
string[] files = Directory.GetFiles(Application.dataPath + "/EasyUI/ExcelFiles", "*.xlsx", SearchOption.TopDirectoryOnly); string staticDataClassCode = ""; try
{
int priority1 = ;
string code;
foreach (string path in files)
{
info = new FileInfo(path);
stream = info.Open(FileMode.Open, FileAccess.Read);
excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
result = excelReader.AsDataSet();
int rowCount = result.Tables[].Rows.Count;
int colCount = result.Tables[].Columns.Count;
string className = result.Tables[].Rows[][].ToString(); staticDataClassCode += " [ProtoMember(" + priority1++ + ")]\n";
staticDataClassCode += " public List<" + className + "> " + className + "List = new List<" + className + ">();\n"; code = "";
code += "using System.Collections;\n";
code += "using System.Collections.Generic;\n";
code += "using ProtoBuf;\n";
code += "[ProtoContract]\n";
code += "public class " + className + "\n";
code += "{\n";
int priority2 = ;
for (int col = ; col < colCount; col++)
{
code += " [ProtoMember(" + priority2++ + ")]\n";
code += " public " + result.Tables[].Rows[][col].ToString() + " " + result.Tables[].Rows[][col].ToString() + ";\n";
}
code += " public " + className + "()\n";
code += " {}\n";
code += "}\n";
WriteClass(Application.dataPath + "/Script/Datas/" + className + ".cs", className, code); excelReader.Close();
stream.Close();
}
code = "";
code += "using System.Collections;\n";
code += "using System.Collections.Generic;\n";
code += "using ProtoBuf;\n";
code += "[ProtoContract]\n";
code += "public class StaticData\n";
code += "{\n";
code += staticDataClassCode;
code += " public StaticData(){}\n";
code += "}\n";
WriteClass(Application.dataPath + "/Script/Datas/StaticData.cs", "StaticData", code);
}
catch (IndexOutOfRangeException exp)
{
Debug.LogError(exp.StackTrace);
}
AssetDatabase.Refresh();
AssetDatabase.SaveAssets();
}
2..生成二进制文件
public static void GenerateBinFile()
{
FileInfo info;
FileStream stream;
IExcelDataReader excelReader;
DataSet result;
string[] files = Directory.GetFiles(Application.dataPath + "/EasyUI/ExcelFiles", "*.xlsx", SearchOption.TopDirectoryOnly);
int row = , col = ;
string name = "", value = "", type = "";
StaticData staticData = new StaticData(); foreach (string path in files)
{
info = new FileInfo(path);
stream = info.Open(FileMode.Open, FileAccess.Read);
excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
result = excelReader.AsDataSet();
int rowCount = result.Tables[].Rows.Count;
int colCount = result.Tables[].Columns.Count; string className = result.Tables[].Rows[][].ToString();
FieldInfo field = staticData.GetType().GetField(className + "List");//获取类中的一个Field
object fieldValue = field.GetValue(staticData);//给这个实例中的Field的代表的属性赋值
IList list = fieldValue as IList; for (row = ; row < rowCount; row++)
{
Type tt = DataManager.Instance.GetType(className);
object obj = System.Activator.CreateInstance(tt); for (col = ; col < colCount; col++)
{
name = result.Tables[].Rows[][col].ToString();
value = result.Tables[].Rows[row][col].ToString();
type = result.Tables[].Rows[][col].ToString(); Debug.Log(className);
FieldInfo ifo = tt.GetField(name);
object cvalue = System.ComponentModel.TypeDescriptor.GetConverter(ifo.FieldType).ConvertFrom(value);
ifo.SetValue(obj, cvalue);
}
if (list != null)
list.Add(obj);
}
excelReader.Close();
stream.Close();
} using (FileStream fstream = File.Create(Application.dataPath + "/StaticDatas.bin"))
{
Serializer.Serialize(fstream, staticData);
}
AssetDatabase.Refresh();
AssetDatabase.SaveAssets();
}
说明一下DataManager.Instance.GetType(className);
Type.GetType(string)会默认从当前程序及搜索类型,而我的类文件是放到了Unity的Editor文件下,Unity会把这个文件识别为属于Editor程序集,但是生成的代码是放到了其他文件夹下Unity会把文件识别为另一个程序集,这个DataManager一定要放到和生成的类文件的相同程序集中。代码如下
using UnityEngine;
using System.Collections;
using System; public class DataManager { private static DataManager _instance;
public static DataManager Instance
{
get
{
if (_instance == null)
_instance = new DataManager();
return _instance;
}
}
public DataManager()
{
_instance = this;
}
public Type GetType(string name)
{
return Type.GetType(name);
}
}
将代码写入文件的方法
private static void WriteClass(string path,string className,string code)
{
System.IO.File.WriteAllText(path, code, System.Text.UnicodeEncoding.UTF8);
}
把动态编译代码的方法也贴出来吧,方便以后用到
private static Assembly compileCode(string fullClassName, string code)
{
//创建编译器
CSharpCodeProvider provider = new CSharpCodeProvider();
//设置编译参数
CompilerParameters paras = new CompilerParameters();
//paras.ReferencedAssemblies.Add("System.Collections.dll");
//paras.ReferencedAssemblies.Add("System.Collections.Generic.dll");
paras.ReferencedAssemblies.Add("System.dll");
paras.ReferencedAssemblies.Add("protobuf-net.dll");
//paras.OutputAssembly = "ScriptData.dll";
//编译成exe还是dll
paras.GenerateExecutable = false;
//是否写入内存,不写入内存就写入磁盘
paras.GenerateInMemory = true;
CompilerResults result = provider.CompileAssemblyFromSource(paras, code);//编译代码
Assembly as1 = result.CompiledAssembly; //获得编译后的程序集
return as1;
}
OK,文件已经生成了,经测试两个10K的Excel文件打包成一个StaticData.bin文件,1K!!!
不过一般游戏中的数据表无论是内容还是数量都远远大于这个数量。所以一般生成的bin文件还要进行压缩,或者用Unity打包,哦了,就先到这把剩下的内容下一帖继续。
http://m.oschina.net/blog/308267
http://dsqiu.iteye.com/blog/1887702
http://www.cnblogs.com/zfanlong1314/p/4197383.html
http://stackoverflow.com/questions/2522376/how-to-choose-between-protobuf-csharp-port-and-protobuf-net
本文固定连接:http://www.cnblogs.com/fly-100/p/4541211.html
C# Unity游戏开发——Excel中的数据是如何到游戏中的 (二)的更多相关文章
- C# Unity游戏开发——Excel中的数据是如何到游戏中的 (三)
本帖是延续的:C# Unity游戏开发——Excel中的数据是如何到游戏中的 (二) 前几天有点事情所以没有继续更新,今天我们接着说.上个帖子中我们看到已经把Excel数据生成了.bin的文件,不过其 ...
- C# Unity游戏开发——Excel中的数据是如何到游戏中的 (四)2018.4.3更新
本帖是延续的:C# Unity游戏开发--Excel中的数据是如何到游戏中的 (三) 最近项目不算太忙,终于有时间更新博客了.关于数据处理这个主题前面的(一)(二)(三)基本上算是一个完整的静态数据处 ...
- 【COCOS2DX-LUA 脚本开发之一】在Cocos2dX游戏中使用Lua脚本进行游戏开发(基础篇)并介绍脚本在游戏中详细用途!
[COCOS2DX-LUA 脚本开发之一]在Cocos2dX游戏中使用Lua脚本进行游戏开发(基础篇)并介绍脚本在游戏中详细用途! 分类: [Cocos2dx Lua 脚本开发 ] 2012-04-1 ...
- excel中的数据粘贴不全到plsql中,excel 粘贴后空白,Excel复制粘贴内容不全
http://zhidao.baidu.com/link?url=pHZQvfWJzI-lQjl4uP86q4GLcpYHu4o-fdjiYegJS0Cy5HEq5oz0YrUye3iHjmv5CJ3 ...
- [置顶] cocos2d-x 3.0游戏开发xcode5帅印博客教学 003.[HoldTail]游戏世界以及背景画面
cocos2d-x 3.0游戏开发xcode5帅印博客教学 003.[HoldTail]游戏世界以及背景画面 写给大家的前言,在学习cocos2d-x的时候自己走了很多的弯路,也遇到了很多很多问题,不 ...
- hbase使用MapReduce操作4(实现将 HDFS 中的数据写入到 HBase 表中)
实现将 HDFS 中的数据写入到 HBase 表中 Runner类 package com.yjsj.hbase_mr2; import com.yjsj.hbase_mr2.ReadFruitFro ...
- sql之将一个表中的数据注入另一个表中
sql之将一个表中的数据注入另一个表中 需求:现有两张表t1,t2,现需要将t2的数据通过XZQHBM相同对应放入t1表中 t1: t2: 思路:left join 语句: select * from ...
- 使用spark将内存中的数据写入到hive表中
使用spark将内存中的数据写入到hive表中 hive-site.xml <?xml version="1.0" encoding="UTF-8" st ...
- SQL语句的使用,SELECT - 从数据库表中获取数据 UPDATE - 更新数据库表中的数据 DELETE - 从数据库表中删除数据 INSERT INTO - 向数据库表中插入数据
SQL DML 和 DDL 可以把 SQL 分为两个部分:数据操作语言 (DML) 和 数据定义语言 (DDL). SQL (结构化查询语言)是用于执行查询的语法. 但是 SQL 语言也包含用于更新. ...
随机推荐
- mac地址静态捆绑,防止arp欺骗
arp -s 192.168.1.101 00-21-CC-D3-D5-FF 缺点,每次关机就还原,所以一般创建批处理文件,开机启动. ping 192.168.1.100 -l 65500 多台肉鸡 ...
- 简单三段式状态机实验1-SOS
一直想从一段式状态机切换到三段式状态机,从书上和网上不断搜寻三段式案例及方法,感觉很简单,就想拿之前做过的实验把一段式改成三段式,可是写起来并非那么简单,很棘手,改完后也没有成功,尤其状态机里面的计数 ...
- JS检测图片的大小
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> < ...
- flexpaper二次开发
1.首先下载FlexPaper的源码.下载地址 2.本人不懂flash,只是百度下,然后自己瞎弄弄的.我用的flash build 4.5 提供个key:1499-4181-9296-6452-299 ...
- python之路:进阶篇
> ) { ; } printf(;} print i >>> >>> == : name == == ...
- nginx location配置(URL)
语法规则: location [=|~|~*|^~] /uri/ { … }= 表示精确匹配,这个优先级也是最高的^~ 表示uri以某个常规字符串开头,理解为匹配 url路径即可.nginx不对url ...
- (简单) POJ 1562 Oil Deposits,BFS。
Description The GeoSurvComp geologic survey company is responsible for detecting underground oil dep ...
- 如何在Ubuntu中使用Eclipse + CDT开发C/C++程序
在Ubuntu中安装Eclipse和CDT步骤如下: 1. 下载资源(都下载到/home/maxw/Download/Eclipse下) A. 下载JRE(Java Runtime Enviro ...
- 如何深入学习CSS
学习CSS有了一定基础后,有的人会觉得好象没有什么学的.因为知道一些基本的理论性的东西.CSS说它容易是因为它的知识点有限.说它难学就在于各浏览器对CSS的支持程度不同.如何深入学习我给出以下几点见意 ...
- VB.NET中网络编程所需组件WinHTTP的添加
VB.NET中网络编程所需组件: WinHTTP组件:项目-->添加引用-->COM选项卡-->Microsoft WinHTTP Services,version 5.1--> ...