Unity 保存数据 PlayerPrefs Json
参考
持久性数据:保存游戏状态与设置
Unity中游戏存档方式
简单的介绍几种在unity中对数据的存储和读档的方法!
一、PlayerPrefs
PlayerPrefs并非是为保存游戏状态而开发的,但我们将讨论其在数据保存中的实用性。PlayerPrefs可在多次游戏之间存储玩家的图像质量、音量或其他非必要数据,将偏好设置储存为一个单独的文件(存储路径因操作系统而异,通常位于无访问限制、由系统托管的文件中)。存储数据通常为简单的键值对,且因其易于访问,所以并不能防止居心叵测的家伙修改文件,又因位于系统文件夹下(如“文档”、“桌面”),很有可能会被意外删除。
PlayerPrefs只需要几行代码便可完成应用,但仅支持Float(浮点数)、Int(整数)和String(字符串)类型的值,从而导致大体量复杂对象的序列化非常困难。当然我们可以将所有数据都转换成支持的数据类型,但在有更好的工具方法时,我并不建议大家这么做。
最后,所有PlayerPrefs会被Unity程序存储在一个文件中,而存档或云存档需要我们在多个路径上储存、接收数据,所以它并不适合处理多个存档。
public void SavePrefs()
{
PlayerPrefs.SetInt("Volume", 50);
PlayerPrefs.Save();
}
public void LoadPrefs()
{
int volume = PlayerPrefs.GetInt("Volume", 0);
}
更多API可以参考官方文档:
https://docs.unity3d.com/cn/2019.4/ScriptReference/PlayerPrefs.html
- 优点:上手简单,存储方便,不用考虑内部实现,适合做小游戏的数据存档(网上一搜,发现很多网友都是用的这种方式。
- 缺点:只支持基本数据类型,无法存储一个类,数组,集合,字典等。不过肯定是可以用一个框架来实现自动赋值的,只是感觉更麻烦一点。
二、JSON
JSON是一种可读性较高的数据格式,可被人及机器理解——这可以是优点,也能是缺点。优点在于开发者可以更轻松地调试存档、创建新数据进行测试,但另一方面,玩家也能也很容易地读取和修改数据。如果游戏具备mod模组功能,则便于读取和修改的数据会非常有用,但其并不利于反作弊。不同的用例有不同的需求,而这类格式上的优缺点正是开发者制定多种数据格式的原因。
JSON作为标准化的数据格式广泛应用到了各种应用程序中,市面上的各色平台都对其有深层次支持,方便了多平台游戏的开发。JSON起初是作为网页浏览器的通信协议而开发的,本质上非常适合用于发送网络数据,也因此很适合用于从服务器后端发送和接收数据。
1.JsonUtility
https://docs.unity3d.com/cn/current/Manual/JSONSerialization.html
JsonUtility是Unity内置的JSON数据序列化和反序列化API。它与PlayerPrefs一样应用简单,但数据本身必须手动保存在文件中或通过网络保存。在有多个存档时,存档可以手动保存到不同的路径之下。而为了方便存档,我编写了一个文件管理器,在示例代码库中免费提供下载。
https://github.com/UnityTechnologies/UniteNow20-Persistent-Data
请注意,JsonUtility并不具备JSON的全部功能,习惯使用JSON数据的用户会发现一些功能缺失。JsonUtility出于设计目的舍弃了部分功能,也因此比其他.NET JSON解决方案更快、更高效。
JsonUtility与其它Unity内置序列化程序一样有一定的限制——即检视器中无法序列化的字段也无法序列化为JSON。此类问题可以借助Plain Old Data类型(即PODS)解决,在保存时将运行时数据类型转换为POD,再将其保存到磁盘。必要时还可使用自定义序列化回应(custom serialization callbakcs)来支持Unity序列化程序默认不支持的数据类型。
自定义序列化官方文档:
https://docs.unity3d.com/cn/current/Manual/script-Serialization-Custom.html
2.EditorJsonUtility
https://docs.unity3d.com/2020.2/Documentation/ScriptReference/EditorJsonUtility.html
在JsonUtility家族中,EditorJsonUtility是另一个实用的工具。JsonUtility本身适用于MonoBehaviour或ScriptableObject对象,而EditorJsonUtility适用于所有Unity引擎的数据类型,我们可以在Unity编辑器中用JSON表示任意对象,也可以反之用JSON文件创建资产。
优点:
- 简单轻量
- 可以满足你要序列化的几乎任何类型数据(除了float必须用double来存)
- 如果要升级版本,可以任意删除之前的字段而不会出现不能解析的情况;可以新增字段且采用你在类中直接赋的值(不用像c#序列化那样手动赋值了)。
缺点:
- 相对PlayerPrefs来说,引入了一个50kb左右的dll。
- 不能序列化float类型。
- 不支持更改字段名。如果更改了,就相当于是两个操作,即删除之前的并新增加一个(这一点很重要)。
三、其他方式
1.EasySave
EasySave是Unity Asset Store上一个广受欢迎的插件,让用户无需编写代码即可保存数据,对初学者尤其友好。插件还具备功能强大、使用灵活的API,也能满足高级用户的需求。软件功能全面、开箱即用,绝对让你物超所值。
2.JSON.Net
JSON.Net是兼容所有DotNet平台、免费开源的JSON应用,并且具备内置JsonUtility所舍弃的功能。标准版本的JSON.Net并不支持所有Unity平台,但Unity Asset Store上的修改版扩充了平台支持。
3.XML
XML是数据格式类似与JSON,具备较高的可读性,以及命名空间这类实用功能。DotNet具备对XML的内置支持。
优点:
- 序列化出来的数据直观,可以序列化类和类中的对象。
- 升级版本后,如果新增了字段,则自动采用你在类中赋给该变量的值。
- 升级版本后,如果删除了之前的字段,则自动忽略之前的字段,而不会像c#序列化一样报错,
缺点:
- 不能序列化字典,二维数组以上的数据
- 比Json更占空间,且引入的dll也更大
4.BinaryFormatter
BinaryFormatter属于DotNet库的一份子,可用于将对象直接储存为二进制文件。但BinaryFormatter带有危险的安全漏洞,所以请不要使用BinaryFormatter。点击下方链接详细了解软件的安全风险。
5.c#序列化
优点:除了静态类型和抽象类型以及类必须标记为[Serializable]的(其实这个不是什么问题了),其他的都可以被序列化:类,数组,集合,字典,类及其子类等。而且序列化之后你也看不懂是什么鬼(哈哈)~~。
缺点:
- 不会调用要序列化类的构造函数(当然可以通过实现ISerializable和IDeserializationCallback接口来实现在序列化和反序列化之前对数据的处理,所以这个不是我放弃它的重点)。
- 在升级版本后,新增一个字段也只是采用系统默认值,而不是我在类中直接赋的值,这导致我需要自己去比较当前版本和之前的每一个版本的版本号,然后再挨个处理每个以前版本的升级,就意味着当前是第N次更新,我要做N-1次if判断并手动赋值(这段话是结合自己的项目记录的,当然也就我看得懂了^^)。
- 而让我放弃它的最终原因是,在升级版本后,如果删除了之前的一个字段,则无法正确解析(反序列化),这种情况就最不能容忍了。我不敢冒这样的风险,保证以后的版本不会删除其中一个字段。或许你会想到“你可以保留啊,然后不管它就是了”,不过鉴于我有个超追求完美的boss,只好放弃。毕竟这还不如XML。
四、数据安全
在涉及安全性问题时,大多数人会首先想到数据加密。然而当数据存储在玩家设备上时,数据加密容易被破解。即便加密数据未被破解,用户也可以使用各色免费工具直接在内存中修改数据。换句话说,我们能断言存储在本地的数据都不安全。
如果想要实现真正的数据安全,最好的选择是将数据保存在用户不能触及的服务器上,应用本身也不能向服务器直接发送数据,以防用户修改。相反的,应用只能向服务器发送指令,由服务器来更改数据、将结果发送回应用。因此我们最好尽早明确数据安全的影响,确定项目的数据结构。