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 语言也包含用于更新. ...
随机推荐
- 网络通信TCP编程实例代码
Makefile: all: gcc -o server server.c -lpthread gcc -o client client.c clean: rm server client serve ...
- HDU 1317(Floyd判断连通性+spfa判断正环)
XYZZY Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submi ...
- 自动化运维工具Ansible详细部署
本文来源:http://sofar.blog.51cto.com/353572/1579894/ 前言 一个由 Python 编写的强大的配置管理解决方案.尽管市面上已经有很多可供选择的配置管理解决方 ...
- Android4.4KitKat支持u盘功能
Android4.4KitKat支持u盘功能 作者: 发布日期:2014-05-14 23:16:13 我来说两句(0) 0 Tag标签:功能 Android U 盘功能实现和分析 u 盘功能实 ...
- Ibatis 3.0 之前使用的都是2.0 3.0与2.0的内容有很大的不同
以前用过ibatis2,但是听说ibatis3有较大的性能提升,而且设计也更合理,他不兼容ibatis2.尽管ibatis3还是beta10的状态,但还是打算直接使用ibatis3.0, ibatis ...
- 使用RGBa和Filter实现不影响子元素的CSS透明背景
点击查看原文 问题 如果我们想要一个元素拥有半透明的背景,我们有两个选择: 使用CSS和 opacity 做一张 24-bit PNG 背景图片 在CSS中使用opacity有两个问题,一是为了适应所 ...
- (中等) POJ 1191 棋盘分割,DP。
Description 将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘.(每次 ...
- (简单) POJ 3076 Sudoku , DLX+精确覆盖。
Description A Sudoku grid is a 16x16 grid of cells grouped in sixteen 4x4 squares, where some cells ...
- windows 下nginx 虚拟主机搭建
需要在 nginx.conf里面引入刚才配置的那个文件 第一步 加东西 http的节点里面加上 一定要注意的是:必须以 ; 结尾 include D:/phpen/nginx-1.3.6/co ...
- 一道关于 precision、recall 和 threshold关系的机器学习题
Suppose you have trained a logistic regression classifier which is outputing hθ(x). Currently, you p ...