Unity编辑器拓展之三十五:如何在Editor下使用单例ScriptableObject

个人博客地址

本文介绍在Editor下使用单例ScriptableObject

ScriptableSingleton GUI官方文档click here!

Unity FilePathAttribute官方文档click here!

前言

相信大家都用过ScriptableObject(以下简称so),这里不过多介绍它了,不过关于ScriptableSingleton,可能就用的不多了,上面有官方文档链接。ScriptableSingleton就是一个单例的so。最近在整理项目中开发的工具,准备集合成一个方便移植的工具库,为了更抽象、可移植性更强,有些工具就得抽象出一个配置文件出来,关于这类配置文件,各个项目可能又不一样,所以这类文件就不适合放在工具库内部。放在工程内、工具库以外是比较合适的做法。那么问题在于,工具库里的工具如何拿到这个配置文件呢?(当然如果配置文件不使用so,也无所谓啦)

正文

可行的方案思考出来两种:

1、定义一个FilePathAttribute(并不是指Unity2020提供的那个),在工具外部定义一个FilePathAttribute的字段指定路径,工具内部通过这个Attribute拿到对应的配置文件路径。
2、使用ScriptableSingleton

第一种方案这里就不演示了,这个方案其实是从GF框架从学习来的,可以参见GF框架的ResourceEditorConfigPathAttribute

第二种方案是Unity提供的方案,如何使用具体参考上面的官方文档。这里介绍下使用时候的坑!!!

以下测试环境Unity2019.4.2f1。

1、新建一个单例so

using UnityEditor;

public class TestScriptableObjectSingleton : ScriptableSingleton<TestScriptableObjectSingleton>
{
    public string UserName;
    public int Age;
}

2、新建一个测试读写上面so的代码

using UnityEditor;

namespace Editor
{
    public class TestLoadSo
    {
        [MenuItem("Tools/Read")]
        public static void Read()
        {
            UnityEngine.Debug.LogError(TestScriptableObjectSingleton.instance.UserName);
            UnityEngine.Debug.LogError(TestScriptableObjectSingleton.instance.Age);
        }
        
        [MenuItem("Tools/Write")]
        public static void Write()
        {
            TestScriptableObjectSingleton.instance.UserName = "user_name";
            TestScriptableObjectSingleton.instance.Age = 18;
        }
    }
}

3、测试gif图

从图上看很正常对吧?写入的数据也能正常的读出来。。。但是,重启Unity后,再执行以下Tool/Read,数据没了,因为Unity内部创建的单例so是不会帮我们保存的。

在访问instance的时候,如果instance为空,会调用一下CreateAndLoad。

然后会通过FilePathAttribute找到该类型定义的文件路径,然而,该FilePathAttribute是internal的,从目前了解来看,直到2020版本,FilePathAttribute才公开。

既然无法使用FilePathAttribute,如果我们自己创建一个该类型的so,那么只会报错存在多个,因为它内部压根就无法找到自定义的那个so,更别提instance能够引用到它了。

解决方案

解决方案就是自己写,毕竟项目现在上不了2020。。。

其实啰嗦这么半天,Editor下单例的so写起来就那么点代码,只不过啰嗦下Unity的坑吧。。。

直接上代码了。

using UnityEditor;
using UnityEngine;

public class ScriptableObjectSingleton<T> : ScriptableObject where T : ScriptableObject
{
    private static T s_Instance;
    public static T Instance
    {
        get
        {
            if (s_Instance == null)
            {
                string[] findAssets = AssetDatabase.FindAssets($"t:{typeof(T).Name}");
                if (findAssets == null || findAssets.Length == 0)
                {
                    Debug.LogError($"Please create ScriptableObject typeof {typeof(T)} first...");
                }
                else if (findAssets.Length > 1)
                {
                    Debug.LogError($"ScriptableObject typeof {typeof(T)} exist multiple,please check they...");
                }
                else
                {
                    s_Instance = AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(findAssets[0]));
                }
            }
            return s_Instance;
        }
    }
}
using UnityEditor;
using UnityEngine;
[CreateAssetMenu(menuName = "ScriptableObjectSingletonTest")]
public class ScriptableObjectSingletonTest : ScriptableObjectSingleton<ScriptableObjectSingletonTest>
{
    public string UserName;
    public int Age;
}

本篇文章,如果有不懂,欢迎留言~

以上知识分享,如有错误,欢迎指出,共同学习,共同进步。如果有不懂,欢迎留言评论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值