使用LitJson进行序列化和反序列化

发表于2020-03-03
评论0 8.1k浏览

好久不见。

 

这是第31篇与游戏开发有关的文章。

 

| 写在最前

最近在写小玩具的时候,遇到了需要将游戏记录到本地、并从本地读取的情况,如:保存游戏战斗录像或是存储、读取游戏存档。有多种方法可以实现这个需求,在这里我使用的是序列化成Json的方法;因为它够简单,结构清晰且可读性强,很方便我们对保存的内容进行直观查看。

 

| 关于LitJson

Json的书写格式就不再介绍了,网络上也有很多第三方库可以帮助我们快速生成和解析Json文件,在此我使用的是LitJson,它比较常用,而且十分易用。

 

LitJson使用简单,通常我们直接使用JsonMapper就可以进行Json的序列化和反序列化了。

 

但是本文记录的是使用JsonWriterJsonReader进行序列化和反序列化的过程。

 

之所以没有使用更简单易用的JsonMapper,而使用LitJson中偏基础些的Reader和Writer,主要是因为:

1、对于一些需要二次处理的内容,JsonWriter和JsonReader用起来更灵活些;

2、洋气。

 

| 关于JsonWriterJsonReader

· JsonWriter

JsonWriter像是模仿手写Json,通过WriteArrayStartWriteArrayEndWriteObjectStartWriteObjectEnd来控制当前所写的是数组或是对象;再通过WritePropertyNameWrite来写键值对,非常容易理解。

 

· JsonReader

可以通过输出JsonReader的读入信息,来快速了解它的工作方式。

QRK5i7iMtxvtqQReai6q.png

某Json的读入打印

 

JsonReader的工作方式可以简单理解为“读到什么告诉你什么”。

 

尽管JsonWriterJsonReader非常容易使用,但在实际运用中,所面对的数据结构通常都较为复杂。

 

本文记录的是在处理相对复杂情况下的一些心得。

 

我们的目标是尝试序列化和反序列化一场SLG战斗(battleField),这场战斗仅包含战斗地图(battleMap)和参战单位(battleUnits)两部分。


 

9PzUlZbANbD4hyV4wd9o.png

一场粗糙的战斗

 

| 创建战斗(战场)

序列化战场的前提是先要真正的创建一场战斗。

 

按照示意图的流程,用代码轻松组织起一场战斗吧。

4xQ169YPVPHDxWdKxkRY.png

创建战斗

 

| 序列化战斗

序列化战斗与创建战斗的套路一致,可简单表示为:序列化战斗 = 序列化地图 + 序列化参战单位

 

为了偷懒,我们为JsonWriter增加一些常用的扩展。

KTeS2dtSxn3JqZc2MK2L.png

准备一些方便使用的函数

 

yARJq3vB7aLDOuGTnZFk.png

逐级序列化战斗

 

战斗序列化完成,让我们将Json导出,看一下结构。

5InJNKS2Cm0J2tvdgYux.png

战场json文件


 

| 反序列化战斗

反序列化序列化而言要麻烦一些,原因在于,对象数组比简单的键值组合要复杂些;因为Reader的读取特点是,你需要想一些办法来记录当前读到的对象、数组都包含什么,以及它们的嵌套关系。

 

但当你把每一个对象、数组都清晰的提取出来后,问题就变成了”我读到的这一个对象、数组或键值对,应该交给谁来处理,并变成什么?“。

 

为了让结构清晰,我们让各单位只做自己负责的事情,比如:战场battleField反序列化json数据时,当读取到了名为battleMap的json对象时,就交给battleMap自己处理,至于这个对象里还嵌套了别的东西(如:包含特殊格子索引的数组),或还想做特殊的处理逻辑(如:标记一些格子为特殊),都交给battleMap类的反序列化接口去解决。

 

同样,为了偷懒,我们也为反序列化增加一些扩展。

Ye3zFYs9PrTbDIBOrlos.png

准备一些方便使用的函数

 

d2NebMt9KYLgtO7DnEMR.png

部分逐级反序列化流程

 

| 验证反序列化

一个相对简单的方法来验证反序列化,是将反序列化生成的战斗,再重新序列化成新的Json文件,再与反序列化前读取的Json文件对比,看是否完全一致。

5uHtuU70bjM1VNnLEHRZ.png

通过对比文件检验反序列化是否出现了错误

 

以上就是使用JsonWriterJsonReader进行序列化及反序列化的一些简单体会。

 

对了,如果使用JsonMapper来做同样的事情会是什么样呢?

 

仅用两行代码就搞定了:

序列化

JsonMapper.ToJson(battleField);

 

反序列化

JsonMapper.ToObject<BattleField>(fieldData);

 

十分的方便!

pBvjdokCHCjlQLYXMAjf.png

... 图源网络

 

| 写在最后

感觉好几年没更新了,都快忘了自己在维护一个公众号的事儿了...水一篇先,惭愧。

 

将Demo工程的Github地址奉上。

https://github.com/elsong823/SerializeHelperDemo

 

其实,LitJson仅是一个工具而已,本文并不是想介绍LitJson的接口都有什么作用及如何使用(也根本没这么做)。

 

我更想表达的东西是:无论一件事情有多复杂,我们总能找到方法去拆解它,用相似的结构去处理、分解它。最终就会发现,我们把它弄得更复杂了,可能这就是程序的魅力吧。

 

非常感谢您能读到这里,下回见。

 

我的公众号 偶尔学学Unity 会特别不定期更新与游戏开发可能有关的文章,欢迎关注,谢谢。

rGLoyTxD3rg7N289h1tB.png
  • 允许他人重新传播作品,但他人重新传播时必须在所使用作品的正文开头的显著位置,注明用户的姓名、来源及其采用的知识共享协议,并与该作品在磨坊上的原发地址建立链接
  • 可对作品重新编排、修改、节选或者以作品为基础进行创作和发布
  • 可将作品进行商业性使用

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引