[Unity3D]的ResourceManager类及其编辑器扩展

为了方便程序中动态加载资源目录中物体,编写了一个ResourceManager中的单例类,使用时需要将其附加到一个游戏物体上。

可以实现对物体的分类,重命名,异步加载。

可用方法如下:

//通过名字和类型加载,类型为0时,不判断类型
ResourceRes<T> Load<T>(string name, ResourceType type = 0) where T : UnityEngine.Object

//通过名字和类型加载所有,类型为0时,不判断类型
T[] LoadAll<T>(string name, ResourceType type = 0) where T : UnityEngine.Object

//通过类型加载所有,可以用与的方式,例如加载两个类型:(ResourceType.BGM|ResourceType.Model)
ResourceRes<T>[] LoadAllFromTypeMask<T>(int typeMask) where T : UnityEngine.Object

//异步通过类型加载所有
public void LoadAllFromTypeMaskAsync<T>(int typeMask, Action<ResourceRes<T>[]> onComplete) where T : UnityEngine.Object

//异步通过名字和类型加载所有
void LoadAsync<T>(string name, Action<ResourceRes<T>> onComplete, ResourceType type = 0) where T : UnityEngine.Object

使用方式:

GameObject obj = ResourceManager.Instance.Load<GameObject>("Main").res;

ResourceManager.Instance.LoadAsync<GameObject>("Main", (res) =>
{
    if (res != null)
    {
        GameObject obj = res.res;
    }
});

这里写图片描述

源码如下:

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

#if UNITY_EDITOR
using UnityEditor;
using System.IO;
#endif

public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
    private static T _Instance;

    public static T Instance
    {
        get
        {
            if (_Instance == null)
            {
                _Instance = FindObjectOfType<T>();
            }
            return _Instance;
        }
    }
}

//物体分类,一个物体可以是多种类型
public enum ResourceType
{
    BGM = 0x0001,
    Model = 0x0002,
    Scene = 0x0004,
    PromptAudio = 0x0008,
}

[System.Serializable]
public class ResourceItem
{
    public string name;//资源名字
    public string path;//资源resources路径
    public ResourceType type;//资源类型

    public ResourceItem(string name, string path, ResourceType type)
    {
        this.name = name;
        this.path = path;
        this.type = type;
    }
}

[Serializable]
public class ResourceRes<T> where T : UnityEngine.Object
{
    public string name;//资源名字
    public T res;//资源

    public ResourceRes(string name, T res)
    {
        this.name = name;
        this.res = res;
    }
}


[Serializable]
public class ResourceList
{
    public List<ResourceItem> value = new List<ResourceItem>();
}


public class ResourceManager : Singleton<ResourceManager>
{
    /// <summary>
    /// 资源配置文件
    /// </summary>
    private string _configFilePath = "configs/resourcemanager";

    public ResourceList _resLst;

    public void Awake()
    {
        LoadConfig();
    }

    private void LoadConfig()
    {
        TextAsset config = Resources.Load<TextAsset>(_configFilePath);
        if (null == config)
        {
            Debug.LogError("LoadConfig config is null");
            return;
        }
        if (string.IsNullOrEmpty(config.text))
        {
            Debug.LogError("LoadConfig config.text is null or empty.");
            return;
        }

        _resLst = JsonUtility.FromJson<ResourceList>(config.text);
        Debug.Assert(null != _resLst, "LoadConfig _audioResLst is null.");
    }

    private ResourceItem GetItemFromName(ResourceList resLst, string name)
    {
        ResourceItem item = resLst.value.Find((rt) =>
        {
            return rt.name == name;
        });

        return item;
    }

    private ResourceItem GetItemFromNameType(ResourceList resLst, string name, ResourceType type)
    {
        ResourceItem item = resLst.value.Find((rt) =>
        {
            return (rt.name == name) && (rt.type == type);
        });

        return item;
    }

    private List<ResourceItem> GetAllResourceItemFromTypeMask(ResourceList resLst, int typeMask)
    {
        return resLst.value.FindAll((t) =>
        {
            return (((int)t.type & typeMask) != 0);
        });
    }

    public ResourceRes<T> Load<T>(string name, ResourceType type = 0) where T : UnityEngine.Object
    {
        ResourceItem item = null;
        if (0 == type)
        {
            item = GetItemFromName(_resLst, name);
        }
        else
        {
            item = GetItemFromNameType(_resLst, name, type);
        }

        if (null == item)
        {
            return null;
        }

        T t = Resources.Load<T>(item.path);
        Debug.Assert(t != null, "srcpath:" + item.path);
        return new ResourceRes<T>(name, t);
    }

    public void LoadAsync<T>(string name, Action<ResourceRes<T>> onComplete, ResourceType type = 0) where T : UnityEngine.Object
    {
        StartCoroutine(AsyncLoading<T>(_resLst, name, onComplete, type));
    }

    public T[] LoadAll<T>(string name, ResourceType type = 0) where T : UnityEngine.Object
    {
        ResourceItem item = null;
        if (0 == type)
        {
            item = GetItemFromName(_resLst, name);
        }
        else
        {
            item = GetItemFromNameType(_resLst, name, type);
        }

        if (null == item)
        {
            return null;
        }

        T[] t = Resources.LoadAll<T>(item.path);
        Debug.Assert(t != null, "srcpath:" + item.path);
        return t;
    }

    public ResourceRes<T>[] LoadAllFromTypeMask<T>(int typeMask) where T : UnityEngine.Object
    {
        ResourceRes<T>[] obj = null;
        List<ResourceItem> resItemLst = GetAllResourceItemFromTypeMask(_resLst, typeMask);
        Debug.Assert(null != resItemLst, "resItemLst is Null");
        if (null != resItemLst)
        {
            List<ResourceRes<T>> tempLst = new List<ResourceRes<T>>();
            T tempObj = null;
            foreach (ResourceItem item in resItemLst)
            {
                tempObj = Resources.Load<T>(item.path);
                Debug.Assert(null != tempObj, "tempObj is Null");
                if (null != tempObj)
                {
                    tempLst.Add(new ResourceRes<T>(item.name, tempObj));
                }
            }

            obj = tempLst.ToArray();
        }

        return obj;
    }

    public void LoadAllFromTypeMaskAsync<T>(int typeMask, Action<ResourceRes<T>[]> onComplete) where T : UnityEngine.Object
    {
        StartCoroutine(AsyncLoadingAllFromTypeMask<T>(_resLst, typeMask, onComplete));
    }

    private IEnumerator AsyncLoadingAllFromTypeMask<T>(ResourceList resLst, int typeMask, Action<ResourceRes<T>[]> onComplete) where T : UnityEngine.Object
    {
        List<ResourceItem> resItemLst = GetAllResourceItemFromTypeMask(resLst, typeMask);
        yield return AsyncLoadingAllFromItems<T>(resItemLst.ToArray(), onComplete);
    }

    private IEnumerator AsyncLoadingAllFromItems<T>(ResourceItem[] resLst, Action<ResourceRes<T>[]> onComplete) where T : UnityEngine.Object
    {
        ResourceRes<T>[] obj = null;
        Debug.Assert(null != resLst, "itemLst is Null");
        bool nextStep = false;
        if (null != resLst)
        {
            List<ResourceRes<T>> tempLst = new List<ResourceRes<T>>();
            foreach (ResourceItem item in resLst)
            {
                nextStep = false;
                while (!nextStep)
                {
                    yield return AsyncLoading<T>(item, (t) =>
                    {
                        if (null != t)
                        {
                            tempLst.Add(t);
                        }
                        nextStep = true;
                    });
                }
            }
            obj = tempLst.ToArray();
        }

        if (null != onComplete)
        {
            onComplete(obj);
        }
    }

    private IEnumerator AsyncLoading<T>(ResourceItem item, Action<ResourceRes<T>> onComplete) where T : UnityEngine.Object
    {
        T obj = null;
        Debug.Assert(null != item, "item is Null");
        if (!string.IsNullOrEmpty(item.path))
        {
            ResourceRequest req = Resources.LoadAsync<T>(item.path);
            Debug.Assert(req != null, "srcpath:" + item.path);
            if (req != null)
            {
                while (!req.isDone)
                {
                    yield return null;
                }

                obj = req.asset as T;
            }
        }
        else
        {
            Debug.Log("srcpath is Null or Empty");
        }

        if (null != onComplete)
        {
            onComplete(new ResourceRes<T>(item.name, obj));
        }

        yield return null;
    }

    private IEnumerator AsyncLoading<T>(ResourceList resLst, string name, Action<ResourceRes<T>> onComplete, ResourceType type = 0) where T : UnityEngine.Object
    {
        ResourceItem item = null;

        if (0 == type)
        {
            item = GetItemFromName(resLst, name);
        }
        else
        {
            item = GetItemFromNameType(resLst, name, type);
        }

        yield return AsyncLoading(item, onComplete);
    }
}

#if UNITY_EDITOR
//编辑器扩展

[CustomEditor(typeof(ResourceManager))]
[CanEditMultipleObjects()]
public class ResourceManagerEdit : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        if (GUILayout.Button("Edit Config"))
        {
            ResourceManagerWindow.ShowWindow();
        }
    }
}

public class ResourceManagerWindow : EditorWindow
{
    [MenuItem("Custom/Resource Mgr")]
    public static void ShowWindow()
    {
        ResourceManagerWindow window = GetWindow<ResourceManagerWindow>("Resource Mgr");
        window.Show();
    }

    [Serializable]
    public class ResourceManagerConfig
    {
        public string configPath = "resources/configs/resourcemanager";
    }

    string editConfigPath = "";
    ResourceManagerConfig editConfig = null;
    ResourceList _lst = null;

    public void OnEnable()
    {
        editConfigPath = Path.Combine(Application.dataPath, "../ProjectSettings/ResourceManagerConfig.json");
        if (File.Exists(editConfigPath))
        {
            string editConfigMsg = File.ReadAllText(editConfigPath);
            editConfig = JsonUtility.FromJson<ResourceManagerConfig>(editConfigMsg);
        }
        if (null == editConfig)
        {
            editConfig = new ResourceManagerConfig();
        }

        Load();
    }

    public void OnDisable()
    {
        Save();

        string editConfigMsg = JsonUtility.ToJson(editConfig);
        File.WriteAllText(editConfigPath, editConfigMsg);
    }

    void Load()
    {
        string path = Path.Combine(Application.dataPath, editConfig.configPath);
        if (File.Exists(path))
        {
            string configMsg = File.ReadAllText(path);
            _lst = JsonUtility.FromJson<ResourceList>(configMsg);
        }
        if (null == _lst)
        {
            _lst = new ResourceList();
        }
    }

    void Save()
    {
        if (!string.IsNullOrEmpty(editConfig.configPath))
        {
            string path = Path.Combine(Application.dataPath, editConfig.configPath);
            if (!Directory.Exists(Path.GetDirectoryName(path)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(path));
            }

            string configMsg = JsonUtility.ToJson(_lst);
            File.WriteAllText(path, configMsg);

            if (File.Exists(path))
            {
                AssetDatabase.ImportAsset("Assets/" + editConfig.configPath, ImportAssetOptions.ForceSynchronousImport);
            }
        }
    }

    Vector2 _scrollPos;
    public void OnGUI()
    {
        GUILayout.Label("Root is Assets folder path.");
        GUILayout.BeginHorizontal();
        GUILayout.Label("Path:", GUILayout.MaxWidth(50));
        editConfig.configPath = GUILayout.TextField(editConfig.configPath);
        if (GUILayout.Button("Load", GUILayout.Width(40), GUILayout.Height(14)))
        {
            Load();
        }
        GUILayout.EndHorizontal();
        GUILayout.BeginVertical();

        GUILayout.BeginHorizontal();
        GUILayout.Label("Name:", GUILayout.Width(100));
        GUILayout.Label("Path:");
        GUILayout.Label("Type:", GUILayout.Width(100));
        GUILayout.EndHorizontal();

        _scrollPos = GUILayout.BeginScrollView(_scrollPos);
        for (int index = 0, cnt = _lst.value.Count; index < cnt; index++)
        {
            GUILayout.BeginHorizontal();
            ResourceItem item = _lst.value[index];

            item.name = GUILayout.TextField(item.name, GUILayout.Width(100));
            item.path = GUILayout.TextField(item.path);
            item.type = (ResourceType)EditorGUILayout.EnumMaskField(item.type, GUILayout.Width(100));
            if (GUILayout.Button("-", GUILayout.Width(20), GUILayout.Height(14)))
            {
                _lst.value.RemoveAt(index);
                --index;
                --cnt;

                continue;
            }

            GUILayout.EndHorizontal();
        }
        GUILayout.EndScrollView();

        if (GUILayout.Button("Add"))
        {
            _lst.value.Add(new ResourceItem("", "", 0));
        }
        GUILayout.EndVertical();
    }
}
#endif