[游戏开发] Unity中使用FlatBuffer

 什么是FlatBuffer

官网: 

GitHub - google/flatbuffers: FlatBuffers: Memory Efficient Serialization LibraryFlatBuffers: Memory Efficient Serialization Library - google/flatbuffersicon-default.png?t=O83Ahttps://github.com/google/flatbuffers

为什么用FloatBuffer,优势在哪?

下图是常规使用的各种数据存储类型的性能对比。 

  1. 对序列化数据的访问不需要打包和拆包——它将序列化数据存储在缓存中,这些数据既可以存储在文件中,又可以通过网络原样传输,而没有任何解析开销;(这是最主要的原因,ProtoBuffer、JSON等均需要拆包和解包)
  2. 内存效率和速度——访问数据时的唯一内存需求就是缓冲区,不需要额外的内存分配。 这里可查看详细的基准测试;
  3. 扩展性、灵活性——它支持的可选字段意味着不仅能获得很好的前向/后向兼容性(对于长生命周期的游戏来说尤其重要,因为不需要每个新版本都更新所有数据);
  4. 最小代码依赖——仅仅需要自动生成的少量代码和一个单一的头文件依赖,很容易集成到现有系统中。再次,看基准部分细节;
  5. 强类型设计——尽可能使错误出现在编译期,而不是等到运行期才手动检查和修正;
  6. 使用简单——生成的C++代码提供了简单的访问和构造接口;而且如果需要,通过一个可选功能可以用来在运行时高效解析Schema和类JSON格式的文本;
  7. 跨平台——支持C++11、Java,而不需要任何依赖库;在最新的gcc、clang、vs2010等编译器上工作良好;

 除了性能上的优势,FlatBuffer还支持把数据序列化成明文Json供开发者校验数据正确性。

游戏开发什么情况选择使用FlatBuffer 

 大量的数据配表,想要高效加载大量数据

FlatBuffer使用流程

  1. 定义FlatBuffer数据格式文件schema
  2. 序列化数据成bytes文件
  3. Unity工程中加入FlatBuffer解析源码
  4. 使用FlatC.exe工具生成C#数据解析代码
  5. 加载bytes数据解析成数据对象。

Schema

FlatBuffer的自定义数据格式文件叫Schema。文件后缀是.fbs,和protobuffer的.proto后缀类似。

Schema支持的语法有

创建MyTestData.fbs文件,放到新建文件夹TestFlatBuffer内

//统计一下所有使用类型
//namespace的作用:1生成C#代码有命名空间  2生成文件夹
namespace MyGame;//attribute字段暂时没看啥作用
attribute "priority";//枚举使用方式1
enum Color : byte { Red = 1, Green, Blue }//枚举使用方式2
enum PhoneType : int {MOBILE = 0,HOME = 1,WORK = 2,
}table Monster {number:string (required);type:int;
}table Weapon {number:string (required);type:int;
}table Pickup {number:string (required);type:int;
}//数据对象可以是Monster、Weapon、Pickup中的任何一个
union TestUnion { Monster, Weapon, Pickup }//自定义三维数据
struct Vec3 {x:float;y:float;z:float;
}//Monster结构中展示了常规值类型数据的使用方法
//展示了在table内使用struct、数组、union、枚举
table DataTable {pos:Vec3;//常规值类型damage:int = 500;hp:short = 100;name:string;friendly:bool = false;//数组的使用方式intArr:[int];//枚举的使用方式,支持写默认值color:Color = Blue;unionTarget:TestUnion;
}table MyTestData {dataTable:[DataTable];
}//root_type字段非常重要
root_type MyTestData;

Flatc.exe文件

flatc文件是干嘛的?它是把schema语法文件生成目标语言代码的程序。

Releases · google/flatbuffers · GitHubFlatBuffers: Memory Efficient Serialization Library - Releases · google/flatbuffersicon-default.png?t=O83Ahttps://github.com/google/flatbuffers/releases 

 新建一个批处理文件exportCSharp.bat去运行这个exe程序

flatc.exe --csharp -o Sample MyTestData.fbs

--csharp代表生成目标语言

-o代表输出文件路径为 Sample文件夹

在PowerSheel中运行这个bat,不在powerSheel运行就双击运行Bat文件,发现有语法错误 

修改53行语法错误继续运行bat,成功后没啥日志

到输出文件夹去看一下

通过图片可以看出,我们在Schema文件里定义的数据类型都生成了一份C#文件,把MyGame文件夹拷贝到Unity项目中就可以解析这些数据啦

打开MyTestData文件简单看一下,反正都是数据格式咱们不需要太关心。

 下载FlatBuffer源码

为何前面已经导出了schema数据代码,还要下载FlatBuffer源码??

因为schema生成的代码是纯数据相关的代码,需要源码去驱动数据代码序列化和反序列化功能。

https://github.com/google/flatbuffersicon-default.png?t=O83Ahttps://github.com/google/flatbuffers 

 把这些C#脚本拷贝到Unity项目中,多余文件可以删掉。

把源码拷贝到项目中后,编译报错

原因是我的FlatBuffer源码使用的是老版本,和flatc.exe代码的版本号不配套,你们的Flatc和FlatBuffers源码都从官网下载,肯定是配套的。

在Unity中使用FlatBuffer

完成前面的工作就可以正式使用FlatBuffer啦 

这是官方文档里推荐的Unity使用FlatBuffer案例

Flatbuffers for Unity + Sample Code | eXiinicon-default.png?t=O83Ahttp://exiin.com/blog/flatbuffers-for-unity-sample-code/

测试工程就只有FlatBuffers源码和我们生成的MyGame数据脚本

整俩按钮测试

创建一个测试文件UseFlatBuffer.cs

using System.IO;
using UnityEngine;
using MyGame;
using Google.FlatBuffers;
using Color = MyGame.Color;public class UseFlatBuffer : MonoBehaviour
{public void Serilized(){//MyTestDatas是个数组,我们假定数据有5条int dataCount = 5;FlatBufferBuilder builder = new FlatBufferBuilder(1);//创建数组对象Offset<DataTable>[] dataTables = new Offset<DataTable>[dataCount];for (int i = 0; i < dataCount; i++){StringOffset testName = builder.CreateString(i.ToString());VectorOffset inventoryVector = DataTable.CreateIntArrVector(builder,new int[]{i * 10 + 1,i * 10 + 2,i * 10 + 3,i * 10 + 4});//创建Union类型和对象TestUnion unionType = TestUnion.Monster;Offset<Monster> monster = Monster.CreateMonster(builder, builder.CreateString("怪物的名字"), 100);//---------------------开始写入数据-------------------------------------------------DataTable.StartDataTable(builder);//创建、写入posOffset<Vec3> pos = Vec3.CreateVec3(builder, 100 * i, 100 * i, 100 * i);DataTable.AddPos(builder,pos);DataTable.AddHp(builder, 2);//short类型DataTable.AddFriendly(builder,true);DataTable.AddName(builder,testName);//string类型//数组的用法DataTable.AddIntArr(builder,inventoryVector);//添加整数数组到对象//枚举的用法DataTable.AddColor(builder,Color.Red);//Union的使用方法DataTable.AddUnionTargetType(builder,unionType);DataTable.AddUnionTarget(builder, monster.Value);dataTables[i] = DataTable.EndDataTable(builder);}//把5条数据塞入VectorOffset,因为最终数据是一个数组VectorOffset dtArr = MyTestData.CreateDataTableVector(builder, dataTables);//开始写入数据MyTestData.StartMyTestData(builder);MyTestData.AddDataTable(builder,dtArr);//结束写入Offset<MyTestData> dtOffset = MyTestData.EndMyTestData(builder);//序列化数据MyTestData.FinishMyTestDataBuffer(builder,dtOffset);byte[] bytes = builder.DataBuffer.ToSizedArray();File.WriteAllBytes("E:\\MyTestData.bytes",bytes);}//反序列化,把数据都打印出来public void Deserilized(){byte[] datas = File.ReadAllBytes("E:\\MyTestData.bytes");ByteBuffer buffer = new ByteBuffer(datas);MyTestData myTestData = MyTestData.GetRootAsMyTestData(buffer);int dtCount = myTestData.DataTableLength;Debug.Log("数据量:" + dtCount.ToString());for (int i = 0; i < dtCount; i++){MyGame.DataTable dt = myTestData.DataTable(i).Value;Vec3 targetPos = dt.Pos.Value;Debug.Log(string.Format("x:{0},y:{1},z{2}",targetPos.X,targetPos.Y,targetPos.Z));for (int j = 0; j < dt.IntArrLength; j++)Debug.Log("intArr: " + dt.IntArr(j).ToString());MyGame.Color color = dt.Color;Debug.Log("color: " + color);}}
}

注意点

1、数据结构支持嵌套自身

table MyTestData {damage:int = 500;data:MyTestData;
}

2、如果你只有一个数据对象,用下面的写法,根数据就是这个结构体,如果你有多个重复对象,则用上面的写法,把它写成一个数组。

table MyTestData {dataTable:[DataTable];
}
root_type MyTestData;
table MyTestData {damage:int = 500;hp:short = 100;name:string;
}
root_type MyTestData;

3、三维数组有简写方式,官网里有写

struct Vec3 {v:[float:3];
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/62675.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL其一,概念学习,可视化软件安装以及增删改查语句

目录 MySQL 1、数据库的概念 2、数据库分类 3、MySQL的安装 4、安装过程中的问题 DataGrip的使用&#xff1a; SQLynx的使用&#xff1a; 5、编写SQL语句 6、DDL语句 7、DML 新增数据&#xff1a; 删除数据&#xff1a; 修改数据&#xff1a; MySQL SQL其实是一门…

05 在 Linux 使用 AXI DMA

DMA简介 DMA 是一种采用硬件实现存储器与存储器之间或存储器与外设之间直接进行高速数据传输的技术&#xff0c;传输过程无需 CPU 参与&#xff08;但是CPU需要提前配置传输规则&#xff09;&#xff0c;可以大大减轻 CPU 的负担。 DMA 存储传输的过程如下&#xff1a; CPU 向…

linux 安装 vsftpd 服务以及配置全攻略,vsftpd 虚拟多用户多目录配置,为每个用户配置不同的使用权限

linux 安装 vsftpd 服务以及配置全攻略&#xff0c;vsftpd 虚拟多用户多目录配置&#xff0c;为每个用户配置不同的使用权限。 linux 安装 vsftpd 服务以及配置全攻略 FTP 是 File Transfer Protocol 的简称&#xff0c;用于 Internet 上的控制文件的双向传输。同时&#xff0…

SQL语句在MySQL中如何执行

MySQL的基础架构 首先就是客户端&#xff0c;其次Server服务层&#xff0c;大多数MySQL的核心服务都在这一层&#xff0c;包括连接、分析、优化、缓存以及所有的内置函数&#xff08;时间、日期、加密函数&#xff09;&#xff0c;所有跨存储引擎功能都在这一层实现&#xff1…

ragflow连不上ollama的解决方案

由于前期wsl默认装在C盘&#xff0c;后期部署好RagFlow后C盘爆红&#xff0c;在连接ollama的时候一直在转圈圈&#xff0c;问其他人没有遇到这种情况&#xff0c;猜测是因为内存不足无法加载模型导致&#xff0c;今天重新在E盘安装wsl 使用wsl装Ubuntu Win11 wsl-安装教程 如…

C#常见错误—空对象错误

System.NullReferenceException&#xff1a;未将对象引用设置到对象的实例 在C#编程中&#xff0c;System.NullReferenceException是一个常见的运行时异常&#xff0c;其错误信息“未将对象引用设置到对象的实例”意味着代码试图访问一个未被初始化或已被设置为null的对象的成…

沁恒CH32V208蓝牙串口透传例程:修改透传的串口;UART-CH32V208-APP代码分析;APP-CH32V208-UART代码分析

从事嵌入式单片机的工作算是符合我个人兴趣爱好的,当面对一个新的芯片我即想把芯片尽快搞懂完成项目赚钱,也想着能够把自己遇到的坑和注意事项记录下来,即方便自己后面查阅也可以分享给大家,这是一种冲动,但是这个或许并不是原厂希望的,尽管这样有可能会牺牲一些时间也有哪天原…

Scala的隐式对象

Scala中&#xff0c;隐式对象&#xff08;implicit object&#xff09;是一种特殊的对象&#xff0c;它可以使得其成员&#xff08;如方法和值&#xff09;在特定的上下文中自动可用&#xff0c;而无需显式地传递它们。隐式对象通常与隐式参数和隐式转换一起使用&#xff0c;以…

矩阵的乘(包括乘方)和除

矩阵的乘分为两种&#xff1a; 一种是高等代数中对矩阵的乘的定义&#xff1a;可以去这里看看包含矩阵的乘。总的来说&#xff0c;若矩阵 A s ∗ n A_{s*n} As∗n​列数和矩阵 B n ∗ t B_{n*t} Bn∗t​的行数相等&#xff0c;则 A A A和 B B B可相乘&#xff0c;得到一个矩阵 …

DVWA亲测sql注入漏洞

LOW等级 我们先输入1 我们加上一个单引号&#xff0c;页面报错 我们看一下源代码&#xff1a; <?php if( isset( $_REQUEST[ Submit ] ) ) { // Get input $id $_REQUEST[ id ]; // Check database $query "SELECT first_name, last_name FROM users WHERE user_id …

机器学习01-发展历史

机器学习01-发展历史 文章目录 机器学习01-发展历史1-传统机器学习的发展进展1. 初始阶段&#xff1a;统计学习和模式识别2. 集成方法和核方法的兴起3. 特征工程和模型优化4. 大规模数据和分布式计算5. 自动化机器学习和特征选择总结 2-隐马尔科夫链为什么不能解决较长上下文问…

想了解操作系统,有什么书籍推荐?

推荐一本操作系统经典书&#xff1a; 操作系统导论 《操作系统导论》虚拟化(virtualization)、并发(concurrency)和持久性(persistence)。这是我们要学习的3个关键概念。通过学习这3个概念&#xff0c;我们将理解操作系统是如何工作的&#xff0c;包括它如何决定接下来哪个程序…

[Collection与数据结构] 位图与布隆过滤器

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

微信小程序横屏页面跳转后,自定义navbar样式跑了?

文章目录 问题原因&#xff1a;解决方案&#xff1a; 今天刚遇到的问题&#xff0c;横屏的页面完成操作后跳转页面后&#xff0c;自定义的tabbar样式乱了&#xff0c;跑到最顶了&#xff0c;真机调试后发现navbar跑到手机状态栏了&#xff0c;它正常应该跟右边胶囊一行。 知道问…

Vivado ILA数据导出MATLAB分析

目录 ILA数据导出 分析方式一 分析方式二 有时候在系统调试时&#xff0c;数据在VIVADO窗口获取的信息有限&#xff0c;可结合MATLAB对已捕获的数据进行分析处理 ILA数据导出 选择信号&#xff0c;单击右键后&#xff0c;会有export ILA DATA选项&#xff0c;将其保存成CS…

《探索形象克隆:科技与未来的奇妙融合》

目录 一、什么是形象克隆 二、形象克隆的技术原理 三、形象克隆的发展现状 四、形象克隆的未来趋势 五、形象克隆的应用场景 六、形象克隆简单代码案例 Python 实现数字人形象克隆 Scratch 实现角色克隆效果&#xff08;以猫为例&#xff09; JavaScript 实现 Scratc…

MATLAB深度学习(七)——ResNet残差网络

一、ResNet网络 ResNet是深度残差网络的简称。其核心思想就是在&#xff0c;每两个网络层之间加入一个残差连接&#xff0c;缓解深层网络中的梯度消失问题 二、残差结构 在多层神经网络模型里&#xff0c;设想一个包含诺干层自网络&#xff0c;子网络的函数用H(x)来表示&#x…

前端入门之VUE--vue组件化编程

前言 VUE是前端用的最多的框架&#xff1b;这篇文章是本人大一上学习前端的笔记&#xff1b;欢迎点赞 收藏 关注&#xff0c;本人将会持续更新。 文章目录 2、Vue组件化编程2.1、组件2.2、基本使用2.2.1、VueComponent 2、Vue组件化编程 2.1、组件 组件&#xff1a;用来实现…

设计模式-装饰器模式(结构型)与责任链模式(行为型)对比,以及链式设计

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1.装饰器模式1.1概念1.2作用1.3应用场景1.4特点1.5类与对象关系1.6实现 2责任链模式2.1概念2.2作用2.3应用场景2.4特点2.5类与对象关系2.6实现 3.对比总结 前言…

操作系统:死锁与饥饿

目录 死锁概念 饥饿与饿死概念 饥饿和死锁对比 死锁类型 死锁条件&#xff08;Coffman条件&#xff09; 死锁恢复方法 死锁避免 安全状态与安全进程序列&#xff1a; 银行家算法&#xff1a; 死锁检测时机&#xff08;了解&#xff09;&#xff1a; 死锁检测 死锁案…