在Unity5中使用Protobuf

射击游戏项目开发笔记 (二)

由于很多的因素,项目改用U3D开发,而项目组目前为止没资深的Unity开发程序员,只能摸着石头过河了.我们网络通信数据使用protobuf的格式,(关于这protobuf的格式分析在上一篇笔记中已经分析得很详细了).简单说明一下目前项目的开发环境与插件的使用情况:

开发脚本: C# (.Net 2.0) 由于我与另一位同事均无C#功底,所以业余时间学习C#必不可少,本人而言已经有了基本的计划.(为什么不是JS 或者BOO,详细翻了一下Assets Unity 基本上大多插件都是用C#写的,Boo更加是第一次听)

开发工具:抛弃官方的Mono 使用VS2012,主要使用了UnityVS插件,注意这个插件现在已经免费了.传送门

GUI:有UGUI与NGUI和GUI三个选择,目前选的是NGUI,主要原因是NGUI的教材网上一抓一大把,由于换引擎的突发性,已经没太多时间给我去看那个比较好用了.(很多事情总是充满无奈)

网络模块:Unity5 提供了一套Net组件,在我花了两天时间去看了它的几个组件之后,发现根本不足以满足我们项目的要求.所以决定使用.Net自带的Socket自己实现.(约莫花了三天的时间)

protobuf的使用

目前C#的库 在google code上有两个:

  1. protobuf-net
  2. protobuf-csharp-port

发现protobuf-net对跨平台的支持似乎略优于protobuf-csharp-port,在社区的评价也好一点,所以选用了protobuf-net.使用protobuf-net基本的步骤是:

  • 编写proto文件

举个梨子,保存为demo.proto,message语法请自行学习

/*
 * package demo;  
 *
 * message People {  
 *    required string name = 1;  
 *    required int32 id = 2;  
 *    required string email = 3;  
 * }
 */
  • 使用protogen.exe生成C#源码文件

基本语法为

// -i: 指定proto文件 可以指定多个
// -o: 制定输出文件路径与文件名
// -ns: 指定源码命名空间,如果不设置则默认为proto的文件名为命名空间
// 若proto文件中有package XXX 参数,则强制命名空间名字为 XXX
protobuf-net\ProtoGen\protogen.exe -i:demo.proto -o:PBMessage\PBMessage.cs -ns:PBMessage
  • 源文件生成DLL动态链接库

基本命令为:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Csc.exe /noconfig /nowarn:1701,1702 /nostdlib+ /
errorreport:prompt /warn:4 /define:TRACE /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll /
reference:protobuf-net.dll /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll /debug:pdbonly /
filealign:512 /optimize+ /out:obj\Release\PBMessage.dll /target:library /utf8output PBMessage.cs Properties\AssemblyInfo.cs

如果不想用命令行解决,也可以直接使用VS创建C#库项目,然后把源文件加到项目里,F5生成.在这一步中 得到PBMessage.dll(dll文件名可随意更改)AssemblyInfo.cs为版本信息文件,可在本文末的下载文件中找到,也可以自行创建一个

  • 预编译序列化库 需要上一步得到的PBMessage.dll

命令如下:

protobuf-net\Precompile\precompile.exe PBMessage.dll -o:PBMessageSerializer.dll -t:PBMessageSerializer

经过前面的步骤之后,我们得到了三个DLL:

  1. protobuf-net.dll 从protobuf-net工具包直接取出,根据不同平台而不同
  2. PBMessage.dll 生成的动态链接库
  3. PBMessageSerializer.dll 预编译序列化库

把这三个库放到 Unity项目的 Assets\Plugins\protobuf文件夹下,如没这个文件夹则自行创建.到此就完成了全部配置工作,接下来是代码使用.方法如下:

/*
 * package demo;  
 *
 * message People {  
 *    required string name = 1;  
 *    required int32 id = 2;  
 *    required string email = 3;  
 * }
 */
public void WriteProtoBuf()
{
    demo.People proto = new demo.People();
    proto.email = "rectvv@gmail.com";
    proto.id = 10086;
    proto.name = "Rect";

    // 序列化
    using (MemoryStream ms = new MemoryStream())
    {
        new PBMessageSerializer().Serialize(ms, proto);
        Byte[] pBuffer = ms.ToArray();
    }
}
public void ReadProtoBuf(Byte[] pBuffer,int nSize)
{
    if (null == pBuffer || 0 >= nSize)
    {
        return;
    }
    // 反序列化
    using (MemoryStream ms = new MemoryStream(pBuffer, 0, nSize))
    {
        demo.People proto =  new PBMessageSerializer().Deserialize(ms, null, typeof(demo.People)) as demo.People;
    }
}

代码非常简单.

整个过程被我整合成一个Bat命令:传送门,只需要把proto文件放到根目录,然后运行Build.bat批处理即可.最后的生成DLL在Bin目录中.

10 评论

  1. 我使用了你的工具,发现很好用!赞一个!
    我是刚接触,能为我解答下疑惑吗?

    这个是协议,那怎么建立和维护连接呢?
    C#有事件驱动的网络框架吗?
    或者,用c#建立与服务端的套接字连接,在一个GameObject的Update()函数里面去读套接字?

    已经非常感谢你了,如果还能帮我解答这个疑惑的话,就不知道该怎么报答你了。只能说,他日游戏赚钱了,请你吃饭:)

    1. “用c#建立与服务端的套接字连接” 我分享过我的一个实现:https://github.com/recter/Unity-Net
      你可参考一下。

  2. 你好,我在最后一步生成Serialize.dll的后,为什么找不到该dll文件了呢,谢谢

    1. 生成过程中有无错误log?输入命令的时候有指定输出路径的。你检查一下是不是输出到默认位置了?

      1. 你好,我之前在http://blog.csdn.net/jk823394954/article/details/47791371做了一个demo,然后跟你的也做了对比,中间过程多没什么问题,可是在Unity中使用的时候出现了这样一个错误:Unhandled Exception: System.Reflection.ReflectionTypeLoadException: The classes in the module cannot be loaded.后面还有巴拉巴拉一大堆,不明白是什么问题,能跟你交流一下吗,谢谢

        1. 1. .net framework版本过高?
          2. unity编辑器里是否选择了 完整支持 .net

          1. 谢谢指点,我将VS的Framework的版本调到2.0,果然可以完美运行了,谢谢!!!

发表评论

电子邮件地址不会被公开。 必填项已用*标注