【Unity】ScriptableObject应用
引言
在游戏开发过程中,我们会经常与数据打交道。在游戏开发过程中,我们会经常与数据打交道。假设现在要做一个肉鸽割草类游戏——吸血鬼幸存者,玩家操控的主角在获取了不同武器后会产生不同类型的攻击,这些攻击武器的速度和伤害各不相同。那么显然我要为每一种武器配置好它的属性值。
实现方式有很多,比如我为每种武器创建预制体,然后写脚本去定义代表子弹各个属性的成员变量,再把脚本挂载到武器预制体上。为了方便在开发时调试我们可以将这些变量声明为 public ,以便我们在编辑器面板中对数据进行改动。
这么做其实是有缺点的:
1) 每生成一个武器就会对原来的预制体进行拷贝,其挂载的脚本同样会被拷贝,因此同样的数据会被拷贝多次。而我们规定同一种武器的数据是相同的,也就是同一种武器,不管生成了多少个,它们都共用一套数据。因此,这种方法会创建多余的数据脚本,造成内存浪费。
2) 如果预制体上的脚本丢失,之前在 Inspector 面板中配置的数据也会消失。
不过解决方法有很多,比如:
- 我们可以创建一个全局的数据管理中心脚本,通过静态变量去调用每种武器的数据。不过这种数据配置方式不能实现数据的持久化,而且必须要打开代码文件进行修改,面对茫茫代码可能不是那么直观。
- 我们还可以用上像 excel,Json,xml 等持久化数据存储的方法,结合 Unity 对准备好的数据文件进行数据读写。这么做的好处是可以实现数据的持久化,比如在游戏过程中修改了数据,退出游戏后下一次打开游戏使用的就是之前修改过的数据。
ScriptableObject。它也能弥补通过挂载继承自 MonoBehaviour 的脚本来配置数据的一些不足。相较于 excel,Json,xml 这类持久化数据存储的方法,它有些额外的优点,但是也存在一些局限性。我将会在接下来的部分详细说明。
什么是ScriptableObject
ScriptableObject 是 Unity 提供的一个数据配置存储基类,它是一个可以用来保存大量数据的数据容器,我们可以将它保存为自定义的数据资源文件。
ScriptableObject 是一个类似 MonoBehaviour 的基类,继承自 UnityEngine.Object 。要想使用它,需要我们写个脚本去继承 ScriptableObject 。需要注意的是,继承自 SctiptableObject 的脚本无法挂载到游戏物体上,毕竟它不是继承自 MonoBehaviour。
ScriptableObject 类的实例会被保存成资源文件(.asset文件),和预制体,材质球,音频文件等类似,都是一种资源文件,存放在 Assets 文件夹下,创建出来的实例也是唯一存在的(单例)。
主要作用
- 数据复用(多个对象用同一个数据,节省性能,避免了每个类都去申请空间,浪费)
- 配置文件(配置游戏中的数据)
- 编辑模式下的数据持久化
应用——吸血鬼幸存者
步骤一、自定义so数据容器
比如现在我们要创建一个角色数据类,用序列化方法使得可在inspecter面板上关联或者编辑成员变量。
1 | using UnityEngine; |
这只是一个类,我们还没有创建数据资源文件
步骤二、创建数据资源文件
方法有两种
1. 为类添加CreateAssetMenu特性
1 | using UnityEngine; |
2. 用静态方法创建数据对象
1 | using UnityEditor; |
在顶部工具栏点击“so”按钮,即可创建文件
数据文件的使用
直接在MonoBehaviour类中作为成员使用
- 通过Inspector关联使用
- 通过Resource.Load取用
SO的生命周期函数
Awake:文件创建时调用
OnDestroy:对象被销毁时调用
OnEnable:创建或加载对象时调用
OnDisable:销毁对象或即将重新加载脚本程序集时调用
OnValidata:编辑器才会调用的函数,unity在加载脚本或者Inspector窗口中更改值时调用
非持久数据
非持久数据指的是不管在编辑器内还是发布后都不会持久化的数据
我们可以根据自己的需求随时创建对应数据对象进行使用
使用SO生成非持久化数据
1 | using UnityEngine; |
非持久数据的优点
节约硬盘空间,仅在内存中使用
ScriptableObject数据持久化
Json结合SO存储数据
1 | using System.IO; |
Json结合SO读取数据
1 | using System.IO; |
SO应用
- 配置数据
SO适合做配置文件,因为配置文件一般是只读的,游戏不会修改配置文件
SO不需要第三方软件,比如Excel,Json编辑器等
- 复用数据
当我们使用大量细粒度的对象时,比如子弹,许多子弹可以共享同一份数据,而不用为每个子弹都分配内存
- 数据带来的多态行为
- 使用单例获取数据