从业以来,也做了有将近十款游戏了吧。其中各个游戏都需要去读取配置,无论这个配置是本地的还是从服务器获取的。而配置的读取方式有很多种,我自己也用过很多种,今天特地来总结一下各种读取方式的实现,以及它们的优缺点吧。
先来看看有哪几种常用的加载方式吧!
从本地数据库读取配置文件
- 从Excel文件中读取配置文件
- 从json文件中读取配置文件
- 从xml文件中读取配置文件
- 从csv文件中读取配置文件
- 使用msgPack读取配置文件
- 使用scriptableObject读取配置文件
别被这么多读取方式吓到,其实常用的也就那么一两种(json和msgPack),只要理解了你会发现它们并不复杂。当我们比较配置的读取方式时,我们实际上是在比较三件事:
确实有游戏从excel中直接读取配置来供游戏使用,但这是个很不明智的选择。为什么这么说呢,我们来看一个对比:
一个包含三个表格的excel文件大小:36KB
上述表格转为json后的文件大小:10KB
就我个人而言,即使excel功能很强大,可读性很高,我还是无法忍受excel这么大的数据放到游戏中。所以我没有深入了解过这种读取方式,也不清楚它的读写速度。
我们先来看一段JSON文件吧:
Example - employees.json
[
{"no": 101, "name": "ruby", "age": 25, "gender": "female"},
{"no": 102, "name": "tom", "age": 30, "gender": "male"},
{"no": 103, "name": "rensanning", "age": 36, "gender": "male"}
]
很简单易读,一个企业的花名单。
json应该是目前最主流的,大家用的最多的方式之一了。因为json体积小,速度快,备受大家伙的宠爱。
至于怎么读取,我们可以使用litJson或者unity内置的JsonUtility类来完成序列化。关于JsonUtility的用法和局限性这篇文章讲的挺详细:(虽然排版不咋滴)
Unity JsonUtility的局限性
但有一点它没提到:JsonUtility无法解析带Bom头的json文件,否则会直接报错,导致游戏无法正常运行下去。具体什么报错,当时忘记记录了,好像是下面的错:
ArgumentException: JSON parse error: Invalid value.
UnityEngine.JsonUtility.FromJson[FakeInfo] (System.String json) (at /Users/builduser/buildslave/unity/build/artifacts/generated/common/modules/JSONSerialize/JsonUtilityBindings.gen.cs:25)
FakeInfo.CreateFromJSON (System.String jsonString) (at Assets/Resources/Scripts/FakeInfo.cs:11)
ContentContainerBuildContent+c__Iterator1.MoveNext () (at Assets/Resources/Scripts/ContentContainerBuildContent.cs:49)
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) (at /Users/builduser/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)
各位用的时候千万要注意。
嗯,json确实很强,读取速度和占用空间都很小。但是这世上没有十全十美的东西,json的可读性和可操作性完全比不上excel啊!毕竟excel可以写各种公式,可以被高手拿来做游戏。那咋办呢?回头去用臃肿的excel吗?
嗯…没错,我们还是要用excel。但这次我们并不直接去读取excel,而是把excel放在工程外部,当填好excel表格后,再通过特殊手段把excel转化为json存储在我们的工程中。这样时间、空间和可读性三全齐美,爽歪歪~
可问题是怎么转换呢?网上有很多方法,有的方法甚至可以直接生成对应的实体类。这里暂且不展开讲了。
我们先来看一段XML文件:
101
rensanning
36
male
102
tom
30
male
103
ruby
25
female
可以观察到,它和json有点像,但是比json冗余了一点,因为它的每个字段都要有开始和结束标签。这也导致了它在时间和空间上的表现都略逊于json。所以还是推荐大家使用json。
CSV(Comma-Separated Values)逗号分隔值文件格式,有时也称为字符分隔值,因为分隔字符也可以不是逗号。其文件以纯文本形式存储表格数据(数字和文本)。
还是先来看一段示例吧:
no,name,age,gender
101,rensanning,36,male
102,tom,30,male
103,ruby,25,female
同样是一段花名单,它和json相比更轻巧了,因为它只使用了逗号作为分隔符,没有任何多余的标签和定义。但这也带来了一个问题,当我们的字段中包含逗号怎么办?凉拌。
所以csv只适用于纯数字的配置文件,或者数据量大但是结构简单的配置文件。这种情况下,它的性能优于json。
而json可以适用于各种情况。
这个是我今天和同学交流后,才知道的东西。三人行,并有我师。古人诚不欺我。
msgPack全称为messagePack。号称比json更小巧更快。就像它官网中所说:
msg摒弃了json中的标识符,转而使用一些特殊的字节码来标识字段。将空间节省到了极致。如上图所示,同样内容msg比json节省了1/3的空间。
各位感兴趣的可以试下这个,很有潜力的东西。
我们上面说了那么多,其实都是依赖外部的文件。这些文件本身无法被Unity识别,需要我们通过一些特定的API去读取、序列化它们。
那有没有Unity专用的存储配置格式呢?
Of course!万能的Unity已经为我们准备了scriptableObject。如图,这是一个可视化的持久化存储数据的容器:
这个方法的优点是可视化,在Unity内就能完成数据配置。同时,ScriptableObject本身就是Object的子类,调用起来很方便,不用像json那样需要我们解析完再组装。
但它也有缺点,如上图所示,那么多字段其实维护起来就比较费劲。更别提真正游戏中的配置文件动辄成本上千个字段。所以说它只适用于一些简单的配置,因为它的编辑灵活性远远不如excel。
最后再提一下注意事项:(好多人都被坑过)
ScriptableObject在真机上是不能被修改的!!!
这个ScriptableObject在真机上不可修改的,就像我们不可以在游戏运行时修改一个shader资源的代码、不可以修改一个纹理资源的像素内容一样,而在Unity Editor里可以修改ScriptableObject是因为Unity的编辑器对它格式的支持,就像使用vs code修改shader和使用ps修改一张纹理一样。
参考文档:
https://answers.unity.com/questions/844423/wwwtext-not-reading-utf-8-text.html
https://www.runoob.com/xml/xml-usage.html
xml,json未必是最好的数据传输方案,csv或许更适合
ScriptableObject 序列化