您现在的位置是:首页 >技术教程 >2023-06-04 Unity ScriptableObject1——ScriptableObject数据文件网站首页技术教程

2023-06-04 Unity ScriptableObject1——ScriptableObject数据文件

蔗理苦 2024-08-13 00:01:03
简介2023-06-04 Unity ScriptableObject1——ScriptableObject数据文件


​ ScriptableObject 是 Unity 提供的一个数据配置存储基类,可以用来保存大量数据的数据模板,类似于可以自定义的数据资源文件模板

​ 它是一个类似 MonoBehavior 的基类,需要继承来进行使用

​ 主要作用:

  1. 数据复用(多个对象用同一个数据)

  2. 配置文件(配置游戏中的数据)

  3. 编辑模式下的数据持久化

​ 优点:

  1. 直接在 Inspector 窗口编辑配置数据,利用它来做配置文件

  2. 处理重复数据,减少数据拷贝时造成的内存占用,利用它来做公共数据

  3. 更方便的处理数据带来的多态行为

一、创建数据模板

​ 创建 ScriptableObject 数据模板,需要进行的操作为:

  1. 创建 C# 脚本,继承 ScriptableObject 类
  2. 在该类中声明成员(变量、方法等)
public class MyData : ScriptableObject
{
    // 可以声明任何类型的成员变量
    // 如果希望在 Inspector 窗口中能够编辑它,需要声明为 public 或添加 SerializeField 特性

    public int   i;
    public float f;
    public bool  b;

    public GameObject obj;
    public Material   m;
    public AudioClip  audioClip;
    public VideoClip  videoClip;

    public void PrintInfo() {
        Debug.Log(i);
        Debug.Log(f);
        Debug.Log(b);
    }
}

​ 声明后,我们边可以在 Inspector 窗口中看到变化

​ 我们可以在其中进行设置,但是这些设置都是默认数据,并没有真正使用他们

image-20230604144929256

​ 这些关联信息都是通过脚本文件对应的 Unity 配置文件 meta 进行记录的,打开该脚本同目录下的 .meta 文件可看到:

image-20230604145315888

​ 目前该数据只是一个数据容器模板,只是规定了需要创建的数据格式,并没有创建数据文件

二、创建数据文件

​ 具体的方法有两种:

  1. 为类添加 CreateAssetMenu 特性,通过菜单创建资源

    • [CreateAssetMenu(fileName, menuName, order)]

      fileName:创建出来的默认数据文件名

      menuName:在 Asset / Create 菜单中显示的名字

      order:在 Asset / Create 菜单中的顺序,通过数字指定排列优先级

    [CreateAssetMenu(fileName = "MyData", menuName = "ScriptableObject/我的数据", order = 0)]
    public class MyData : ScriptableObject 
    {
        ...
    }
    

    ​ 在 Project 窗口中右键即可找到对应目录创建数据文件:

    image-20230604150235308

    ​ 创建出来的文件是实实在在的独立数据文件 .asset,可以在 Inspector 面板中编辑其数据。

    image-20230604150321416
  2. 利用 ScriptableObject 的静态方法创建数据对象,然后将数据对象保存在工程目录下

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class ScriptableObjectTool
{
    [MenuItem("ScriptableObject/CreateMyData")]
    public static void CreateMyData()
    {
        // 书写创建数据资源文件的代码
        MyData asset = ScriptableObject.CreateInstance<MyData>();
        
        // 通过编辑器API 根据数据创建一个数据资源文件
        AssetDatabase.CreateAsset(asset, "Assets/Resources/MyDataTest.asset");
        
        // 保存创建的资源
        AssetDatabase.SaveAssets();
        
        // 刷新界面
        AssetDatabase.Refresh();
    }
}

​ 在菜单窗口中即可创建,效果和方法 1 一样。

​ 但是由于引用了 UnityEditor 命名空间,需要将该脚本放在 Editor 文件夹下,否则项目打包会失败。

image-20230604150744685

​ 方法 1 在项目使用中更常用,方法 2 在 Unity 编辑器开发中更常见。

三、使用数据文件

(一)直接关联使用

​ 在继承 MonoBehaviour 类中申明数据容器类型的成员,在 Inspector 窗口进行关联

public class Lesson2 : MonoBehaviour
{
    public MyData data;
}
image-20230604151604644

(二)加载数据使用

​ 使用代码加载数据文件资源

​ Resources、AB包、Addressables 都支持加载继承 ScriptableObject 的数据文件

​ 以 Resources 为例,将数据文件放入 Resources 文件夹下,之后使用代码加载。

image-20230604151857695
public class Lesson2 : MonoBehaviour
{
    public MyData data;
    
    private void Start() {
        data = Resources.Load<MyData>("ScriptableObject/MyDataTest");
        data.PrintInfo();
    }
}

(三)生命周期函数

​ ScriptableObject 和 MonoBehavior 类似,也存在生命周期函数

​ 但是生命周期函数的数量更少,主要做了解,一般使用较少

  • Awake:数据文件创建时调用
  • OnDestroy:ScriptableObject 对象将被销毁时调用
  • OnDisable:ScriptableObject 对象销毁时、即将重新加载脚本程序集时调用
  • OnEnable:ScriptableObject 创建或者加载对象时调用
  • OnValidate:编辑器才会调用的函数,Unity 在加载脚本或者 Inspector 窗口中更改值时调用
public class MyData : ScriptableObject
{
    // 可以声明任何类型的成员变量
    // 如果希望在 Inspector 窗口中能够编辑它,需要声明为 public 或添加 SerializeField 特性

    public int   i;
    public float f;
    public bool  b;

    public GameObject obj;
    public Material   m;
    public AudioClip  audioClip;
    public VideoClip  videoClip;
    
    private void Awake() {
        Debug.Log("数据文件创建时会调用");
    }

    private void OnEnable() { }

    private void OnDisable() { }

    private void OnDestroy() { }

    private void OnValidate() {
        Debug.Log("123");
    }

    public void PrintInfo() {
        Debug.Log(i);
        Debug.Log(f);
        Debug.Log(b);
    }
}
image-20230604152516958

用途:

  1. 编辑器中的数据持久化

    通过代码修改数据对象中内容,会影响数据文件,相当于达到了编辑器中数据持久化的目的
    (该数据持久化只是在编辑模式下的持久,发布运行时并不会保存数据)

  2. 复用数据

    如果多个对象关联同一个数据文件

    相当于他们复用了一组数据,内存上更加节约空间

​ 创建出来的数据资源文件,可以理解成一种记录数据的资源

​ 它的使用方式,和 Unity 中其它资源规则是一样的,比如:预设体、音频文件、视频文件、动画控制器文件、材质球等等

​ 只不过通过继承 ScriptableObject 类生成的数据资源文件,它主要是和数据相关的

四、非持久化特性

​ ScriptableObject 的非持久化指的是不管在编辑器模式还是在发布后,下次运行程序后之前修改的数据都不会存储下来

​ 通过 ScriptableObject 中的静态方法 ScriptableObject.CreateInstance() 创建数据文件来使用,就好像直接 new 一个数据结构类对象,其构造函数在 ScriptableObject 模板中定义。

data = ScriptableObject.CreateInstance("MyData") as MyData;
data = ScriptableObject.CreateInstance<MyData>();
data.PrintInfo();
  • 该方法可以在运行时创建出指定继承 ScriptableObject 的对象
  • 该对象只存在于内存当中,可以被 GC 回收,调用一次就创建一次

意义:

  • 只希望在运行时能有一组唯一的数据可以使用,但又不希望保存为数据资源文件浪费硬盘空间
  • 只在运行时使用,在编辑器模式下也不会保存在本地

​ 对于 ScriptableObject 的数据,由于它在游戏发布运行过程中无法被持久化,可以利用 PlayerPrefs、XML、Json、2进制等等方式,让其可以达到被真正持久化的目的。

但是并不建议使用 ScriptableObject 来做数据持久化,有点画蛇添足

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。