个人博客地址
文章目录
本文介绍在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的unity单例模式,从目前了解来看,直到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;
}
本篇文章,如果有不懂,欢迎留言~
以上知识分享,如有错误unity单例模式,欢迎指出,共同学习,共同进步。如果有不懂技能特效,欢迎留言评论!
文章来源:https://blog.csdn.net/qq_26999509/article/details/110279900