unity资源管理器设计

资源管理器,顾名思义,就是管理游戏中的所有资源,包括加载资源,回收资源,销毁资源等等。下面这个资源管理器主要提供了对assetbundle异步加载功能,Resources的加载没有放在里面。

创新互联是专业的拉孜网站建设公司,拉孜接单;提供网站设计、成都网站建设,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行拉孜网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!


一.使用方法

1.在进入游戏前调用Init(),加载一个资源的名称列表

2.调用AsynGetAsset(string name, Action callback)方法(异步)


说明,这里的资源列表是从bundle_list列表中解析出来的,并且有一个manifest文件用来查找加载依赖的资源,所以,如果要使用这个资源管理器需要将您的资源进行依赖打包assetbundle,可以参考我以前的文章。http://chenshuhb.blog.51cto.com/6087203/1836562

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

using System;

using System.IO;

using LitJson;

using UnityEngine.SceneManagement;

/**

 * 资源管理器

 * 

 * 功能:

 * 1.加载基础配置数据

 * 2.为各个模块提供基础数据接口,供各个模块调用

 * 3. assetbundle,prefab资源的加载

 * 

 **/

public class ResourceManager : Singleton 

{

    //版本文件名

    private static readonly string VERSION_FILE = "resource_version";

    //assetbundle 路径

    private string BUNDLE_PATH = "";

    //本地Resource路径

    private string LOCAL_RES_PATH = "";

    private const string assetTail = ".unity3d";

    //版本文件

    private JsonData jdVersionFile = null;

    ///

    /// 资源文件字典

    /// key:资源名,value:资源路径

    ///

    private Dictionary dicRes = new Dictionary();

    ///

    /// 资源目录字典,需要获取目录下的所有资源

    ///

    private Dictionary dicResDir = new Dictionary();

    ///

    /// 用来存放加载出来的依赖资源的AssetBundle

    ///

    Dictionary dicDepenceAssetBundles = new Dictionary();

    ///

    /// 依赖资源名称(路径)list

    ///

    List dependenceBundleNames = new List();

    ///

    /// bundle资源的总manifest

    ///

    private AssetBundleManifest m_manifest = null;

    ///

    /// 已经加载完成的依赖资源的数量

    ///

    int finishedDependenceCount = 0;

    ///

    /// 所有依赖资源的数量

    ///

    int allDependenceCount = 0;

    #region LoadAssetBundle

    ///

    /// 初始化

    ///

    public void Init()

    {

#if UNITY_EDITOR && UNITY_ANDROID

        BUNDLE_PATH = "file:///" + Application.persistentDataPath + "/res/";

#elif UNITY_EDITOR && UNITY_IOS

        BUNDLE_PATH = Application.streamingAssetsPath + "/ios/";

#elif  UNITY_EDITOR_WIN

        BUNDLE_PATH = "file:///" + Application.streamingAssetsPath + "/windows/";

#elif UNITY_ANDROID

        BUNDLE_PATH = "file://" + Application.persistentDataPath + "/res/";

#elif UNITY_IOS

        BUNDLE_PATH = Application.persistentDataPath + "/res/";

#endif

        LOCAL_RES_PATH = Application.persistentDataPath + "/res/";

        loadResVersion();

    }

    ///

    /// 加载资源版本文件

    ///

    private void loadResVersion()

    {

        string version;

        if (File.Exists(LOCAL_RES_PATH + VERSION_FILE))

            version = File.ReadAllText(LOCAL_RES_PATH + VERSION_FILE);

        else

            return;

        jdVersionFile = JsonMapper.ToObject(version);

        if (null == jdVersionFile)

            Debug.LogError("Config file is null");

        parse(jdVersionFile);

    }

    #region 加载资源方法

    ///

    /// 获取资源

    ///

    /// 资源名

    ///

    public void AsynGetAsset(string name, Action callback)

    {

        name = name + assetTail;

        if (!dicRes.ContainsKey(name))

        {

            Debug.Log("AsynGetAsset: The asset " + name + " does not exist!");

            if (null != callback)

                callback(null);

        }

        string path = dicRes[name];

        Game.Instance.StartCoroutine(LoadAssetBundle(path, (obj) =>

            {

                callback(obj);

            }));

    }

    ///

    /// 释放依赖资源

    ///

    public void UnloadUnusedAssetbundle()

    {

        foreach (KeyValuePair kvp in dicDepenceAssetBundles)

        {

            AssetBundle ab = kvp.Value;

            if (null != ab)

                ab.Unload(false);

        }

        dicDepenceAssetBundles.Clear();

    }

    #endregion

    ///

    /// 要加载的资源名称列表

    ///

    List assetNameList = new List();

    ///

    /// 资源是否已经加载完成

    ///

    bool isOk = true;

    ///

    /// 加载目标资源

    ///

    ///

    ///

    IEnumerator LoadAssetBundle(string name, Action callback)

    {

        assetNameList.Add(name);

        Action> action = (depenceAssetBundles) =>

        {

            string realName = name;// this.GetRuntimePlatform() + "/" + name;//eg:Windows/ui/panel.unity3d

            LoadResReturnWWW(realName, (www) =>

            {

                int index = realName.LastIndexOf("/");

                string assetName = realName.Substring(index + 1);

                //去掉".unity3d"后缀

                assetName = assetName.Replace(assetTail, "");

                //去掉扩展名

                //int extIndex = assetName.LastIndexOf(".");

                //string extName = assetName.Substring(extIndex);

                //assetName = assetName.Replace(extName, "");

                AssetBundle assetBundle = www.assetBundle;

                //重新给material 的Shader赋值

                resetShader(assetBundle);

                UnityEngine.Object obj = null;

                if (null != assetBundle)

                    obj = assetBundle.LoadAsset(assetName);//LoadAsset(name),这个name没有后缀,eg:panel

                else

                    Debug.Log("assetBundle is null assetName is " + assetName);

                //重新给material 的Shader赋值

                resetShader(obj);

                if (null != assetBundle)

                    assetBundle.Unload(false);//卸载资源内存

                //加载目标资源完成的回调

                callback(obj);

            });

            isOk = true;

        };

        while (assetNameList.Count > 0)

        {

            if (isOk)

            {

                isOk = false;

                string _name = assetNameList[0];

                assetNameList.RemoveAt(0);

                LoadDependenceAssets(_name, action);

            }

            yield return null;

        }

    }

    ///

    /// 加载目标资源的依赖资源

    ///

    ///

    ///

    private void LoadDependenceAssets(string targetAssetName, Action> action)

    {

        //Debug.Log("LoadDependenceAssets : targetAssetName is " + targetAssetName);

        Action dependenceAction = (manifest) =>

        {

            if (null == m_manifest)

                m_manifest = manifest;

            excuteLoad(targetAssetName, manifest, action);

        };

        if (null != m_manifest)

            excuteLoad(targetAssetName, m_manifest, action);

        else

            LoadAssetBundleManifest(dependenceAction);

    }

    ///

    /// 递归加载依赖

    ///

    void excuteLoad(string targetAssetName, AssetBundleManifest manifest, Action> action)

    {

        finishedDependenceCount = 0;

        dependenceBundleNames.Clear();

        string[] de = manifest.GetAllDependencies(targetAssetName);

        allDependenceCount = de.Length;

        //如果要加载的资源没有依赖资源,直接回调返回

        if (allDependenceCount == 0)

        {

            action(null);

        }

        else

            loadSubDependence(targetAssetName, manifest, action, allDependenceCount);//, ref depenceAssetBundles, ref dependenceBundleNames);

    }

    ///

    /// 加载依赖

    ///

    ///

    ///

    ///

    void loadSubDependence(string targetAssetName, AssetBundleManifest manifest, Action> action,

        int allDependenceCount)//,ref Dictionary depenceAssetBundles,ref List dependenceBundleNames)

    {

        string[] dependences = manifest.GetDirectDependencies(targetAssetName);

        int length = dependences.Length;

        if (length == 0)

        {

            //没有依赖

            return;

        }

        else

        {

            //有依赖,加载所有依赖资源

            for (int i = 0; i < length; i++)

            {

                string dependenceAssetName = dependences[i];

                //递归                        

                loadSubDependence(dependenceAssetName, manifest, action, allDependenceCount);//,ref depenceAssetBundles,ref dependenceBundleNames);

                //判断资源是否已经被加载过

                if (dependenceBundleNames.Contains(dependenceAssetName))

                    continue;

                dependenceBundleNames.Add(dependenceAssetName);

                if (!dicDepenceAssetBundles.ContainsKey(dependenceAssetName))

                {

                    //加载

                    LoadResReturnWWW(dependenceAssetName, (www) =>

                    {

                        int index = dependenceAssetName.LastIndexOf("/");

                        string assetName = dependenceAssetName.Substring(index + 1);

                        //去掉".unity3d"后缀

                        assetName = assetName.Replace(assetTail, "");

                        //去掉扩展名

                        //int extIndex = assetName.LastIndexOf(".");

                        //string extName = assetName.Substring(extIndex);

                        //assetName = assetName.Replace(extName, "");

                        AssetBundle assetBundle = www.assetBundle;

                        //重新给material 的Shader赋值

                        resetShader(assetBundle);

                        if (null == assetBundle)

                            Debug.LogError("null == assetBundle : " + dependenceAssetName);

                        UnityEngine.Object obj = null;

                        //try

                        //{

                            obj = assetBundle.LoadAsset(assetName);

                        if (dicAtlasObj.ContainsKey(assetName))

                        {

                            if (obj == null)

                            {

#if REALMA_ONGUI_DEBUG

                                OnGUIDebug.AddMsg("atlas null name is " + assetName);

#endif

                                Debug.LogError("atlas null name is " + assetName);

                            }

                            else

                                dicAtlasObj[assetName] = obj;

                        }

                            

                        //重新给material 的Shader赋值

                        resetShader(obj);

                        if (!dicDepenceAssetBundles.ContainsKey(dependenceAssetName))

                            dicDepenceAssetBundles.Add(dependenceAssetName, assetBundle);

                        finishedDependenceCount++;

                        //依赖都加载完了

                        if (finishedDependenceCount == allDependenceCount)

                        {

                            action(dicDepenceAssetBundles);

                        }

                    });

                }

                else

                {

                    finishedDependenceCount++;

                    //依赖都加载完了

                    if (finishedDependenceCount == allDependenceCount)

                    {

                        action(dicDepenceAssetBundles);

                    }

                }

            }

        }

    }

    public UnityEngine.Object GetAtlasObj(string name)

    {

        if (dicAtlasObj.ContainsKey(name))

            return dicAtlasObj[name];

        return null;

    }

    //UnityEditor 在 Android 下打出来的 Android 的 Assetbundle,加载之后 Shader 不能正确的执行!!!

    //解决办法就是,在 Assetbundle Load完之后,遍历 Material ,把所有的 Shader 都重新 Load 赋值一次。

    //通过Assetbundle加载出来的资源有两种类型需要处理:

    //1.如果加载出来的是材质,那么可以对shader进行赋值

    //2.如果加载出来的是GameObject,那么需要获取到Renderer组件下的所有材质,再对每个材质的shader赋值

    ///

    void resetShader(UnityEngine.Object obj)

    {

        List listMat = new List();

        listMat.Clear();

        if (obj is Material)

        {

            Material m = obj as Material;

            listMat.Add(m);

        }

        else if (obj is GameObject)

        {

            GameObject go = obj as GameObject;

            Renderer rend = go.GetComponent();

            if (null != rend)

            {

                Material[] materialsArr = rend.sharedMaterials;

                foreach (Material m in materialsArr)

                    listMat.Add(m);

            }

        }

        for (int i = 0; i < listMat.Count; i++)

        {

            Material m = listMat[i];

            if (null == m)

                continue;

            var shaderName = m.shader.name;

            var newShader = Shader.Find(shaderName);

            if (newShader != null)

                m.shader = newShader;

            else

                Debug.LogWarning("unable to refresh shader: " + shaderName + " in material " + m.name);

        }

    }

    ///

    /// 给assetBundle中的材质的shader重新赋值

    ///

    ///

    void resetShader(AssetBundle assetBundle)

    {

        if (null == assetBundle)

            return;

        var materials = assetBundle.LoadAllAssets(typeof(Material));

        foreach (Material m in materials)

        {

            var shaderName = m.shader.name;

            var newShader = Shader.Find(shaderName);

            if (newShader != null)

                m.shader = newShader;

            else

                Debug.LogWarning("unable to refresh shader: " + shaderName + " in material " + m.name);

        }

    }

    ///

    /// 加载AssetBundleManifest

    ///

    ///

    private void LoadAssetBundleManifest(Action action)

    {

        string manifestName = this.GetRuntimePlatform();

        LoadResReturnWWW(manifestName, (www) =>

        {

            AssetBundle assetBundle = www.assetBundle;

            UnityEngine.Object obj = assetBundle.LoadAsset("AssetBundleManifest");

            assetBundle.Unload(false);

            AssetBundleManifest manif = obj as AssetBundleManifest;

            action(manif);

        });

    }

#endregion

#region ExcuteLoader

    public void LoadResReturnWWW(string name, Action callback)

    {

        string path = "";

#if UNITY_EDITOR_WIN

        path = BUNDLE_PATH + name;

#elif UNITY_ANDROID

        path = BUNDLE_PATH + name;

#endif

        Game.Instance.StartCoroutine(LoaderRes(path, callback));

    }

    IEnumerator LoaderRes(string path, Action callback)

    {

        WWW www = new WWW(path);

        yield return www;

        if (!string.IsNullOrEmpty(www.error))

        {

            Debug.Log("www.error is " + www.error);

        }

        if (www.isDone)

        {

            callback(www);

        }

    }

#endregion

    ///

    /// 解析版本文件

    ///

    void parse(JsonData jd)

    {

        JsonData resInfos = null;

        if (jd.Keys.Contains("resource"))

            resInfos = jd["resource"];

        if (null == resInfos)

        {

            Debug.LogError("解析资源版本文件出错");

            return;

        }

        string[] resNames = new string[resInfos.Count];

        resInfos.Keys.CopyTo(resNames, 0);

        for (int i = 0; i < resNames.Length; i++)

        {

            string name = resNames[i].Substring(resNames[i].LastIndexOf("/") + 1);

            if (!dicRes.ContainsKey(name))

                dicRes.Add(name, resNames[i]);

        }

    }

#region Util

    ///

    /// 平台对应文件夹

    ///

    ///

    private string GetRuntimePlatform()

    {

        string platform = "";

        if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor)

        {

            //platform = "Windows";

            platform = "android";

        }

        else if (Application.platform == RuntimePlatform.Android)

        {

            platform = "android";

        }

        else if (Application.platform == RuntimePlatform.IPhonePlayer)

        {

            platform = "ios";

        }

        else if (Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor)

        {

            platform = "osx";

        }

        return platform;

    }

#endregion

}

肯定还有更好的和更完整的资源管理方案,在此跪求大神分享。


名称栏目:unity资源管理器设计
浏览路径:http://ybzwz.com/article/gpjgch.html