Unity实现动态资源加载的4种方式

为了熟悉一下资源加载的API,做了一个加载图片的小demo,实现了4种加载图片方式,并且把同步与异步做了区分。

使用unity开发游戏的过程中,资源的加载一直都是需要重点关注的。unity一共提供了5种资源加载的方式,分别是Resources(只能加载Resources目录中的资源),AssetBundle(只能加载AB资源,当前设备允许访问的路径都可以),WWW(可以加载任意处资源,包括项目外资源(如远程服务器)),AssetDatabase(只能加载Assets目录下的资源,但只能用于Editor),UnityWebRequest(可以加载任意处资源,是WWW的升级版本)。关于加载的的具体方法建议直接看Unity的API,讲解的比较明白,这里提一下同步与异步加载的意思与优缺点:

同步:并不是按字面意思的同时或一起,而是指协同步调,协助、相互配合。是按先后顺序执行在发出一个功能调用时,在没有得到返回结果之前一直在等待,不会继续往下执行。异步:刚好和同步相反,也就是在发出一个功能调用时,不管没有没得到结果,都继续往下执行,异步加载至少有一帧的延迟。

同步的优点:管理方便,资源准备好可以及时返回。缺点:没有异步快。
异步的优点:速度快与主线程无关。缺点:调用比较麻烦,最好的做法是使用回调。

在UnityWebRequest和WWW的使用过程中使用了回调,为了方便以后自己使用,贴一下代码:

public interface IResourcesLoadingMode  {
    void ResourcesLoading<T>(T t,string path, bool IsAsync) where T:UnityEngine.Object;
    void ResourcesUnLoading<T>(T t)where T:UnityEngine.Object;
	
}

然后是资源加载的基类:

public class ResourcesLoadingMode : IResourcesLoadingMode
{
    public Image Img;
    public MonoBehaviour MB;
 
    public virtual void ResourcesLoading<T>(T t,string path, bool IsAsync) where T:UnityEngine.Object
    {
        throw new NotImplementedException();
    }
 
    public virtual void ResourcesUnLoading<T>(T t) where T : UnityEngine.Object
    {
        throw new NotImplementedException();
    }
}

这里的monoBehaviour是因为整个资源加载器没有继承MonoBehaviour,在异步加载的时候可以把上层控制层的MonoBehavior拿过来,以便可以调用协程实现异步加载。这是一种解决方案,在老大的教导下采用了第二种使用回调函数的方案。

Resouces方式:

public override void ResourcesLoading<T>(T t,string path, bool IsAsync) 
    {
 
       if (IsAsync == false)
        {
            T load = Resources.Load<T>(path);
            t = load;
            Debug.Log("===="+path+"====");
            if (t.GetType() == Img.sprite.GetType())
            {
                Img.sprite = t as Sprite;
                Resources.UnloadAsset(t);
            }
        }
        else
        {
            T load = Resources.LoadAsync<T>(path).asset as T;
            t = load;
            if (t.GetType() == Img.sprite.GetType())
            {
                Img.sprite = t as Sprite;
                Resources.UnloadAsset(t);
            }
        }
    }

AssetDatabase方式:

public override void ResourcesLoading<T>(T t,string path, bool IsAsync)
    {
        if (IsAsync==false)
        {
            //s=string.Format( "Assets/Image/{0}.jpg",Index.ToString())
            T load = AssetDatabase.LoadAssetAtPath<T>(path);
            Debug.Log(path);
            t = load;
            Debug.Log(t.name);
            if (t.GetType() == Img.sprite.GetType())
            {
                Img.sprite = t as Sprite;
                Resources.UnloadAsset(t);
            }
            else
            {
                Debug.Log(t.name);
            }
        }
 
        else
        {
            Debug.Log("assetdatabase没有异步加载");
        }
    }

WWW方式:

public override void ResourcesLoading<T>(T t,string path,bool isAsync)
    {
        if (isAsync == true)
        {
          // MB.StartCoroutine(WWWLoad());
        }
        else
        {
            Debug.Log("----WWW没有同步加载----");
        }
    }
 
    public override void ResourcesUnLoading<T>(T t)
    {
        base.ResourcesUnLoading<T>(t);
       
    }
 
    public static IEnumerator WWWLoad(string url, Action<WWW>callback)
    {
        Debug.Log("----WWW协程调用----");
        //string url = string.Format(@"file://{0}/{1}.jpg", Application.streamingAssetsPath, Index.ToString());
        WWW www = new WWW(url);
        yield return www;
        callback.Invoke(www);
        yield return null;
    }

WWW方式的回调(上层的逻辑来决定需要加载什么资源,写在回调函数里):


/// <summary>
    /// WWW回调函数
    /// </summary>
    /// <param name="obj"></param>
    private void WWWcallback(object obj)
    {
        WWW www = obj as WWW;
        Texture2D tex = www.texture;
        BG.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
        Debug.Log("----callback调用----");
        www.Dispose();
    }

UnityWebRequest方式:

public override void ResourcesLoading<T>(T t,string path,bool isAsync)
    {
        
        if (isAsync==false)
        {
            Debug.Log("unityWebRequest没有同步加载");
        }
    }
 
    public override void ResourcesUnLoading<T>(T t)
    {
        base.ResourcesUnLoading<T>(t);
    }
 
    public static IEnumerator UnityWebRequestLoad(string url,Action<UnityWebRequest>callback)
    {
        //string url =string.Format( @"file://{0}/{1}.jpg", Application.streamingAssetsPath,Index.ToString());
        UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture(url);
        yield return webRequest.SendWebRequest();
        if (webRequest.isNetworkError || webRequest.isHttpError)
        {
            Debug.Log(webRequest.error);
        }
        else
        {
            callback.Invoke(webRequest);
            yield return null;
            //Texture2D tex = DownloadHandlerTexture.GetContent(webRequest);
            //Img.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
        }
    }
}

UnityWebRequest的回调:

 /// <summary>
    /// UnityWebRequest回调函数
    /// </summary>
    /// <param name="obj"></param>
    private void unityWebRequestcallback(object obj)
    {
        UnityWebRequest request = obj as UnityWebRequest;
        Texture2D tex = DownloadHandlerTexture.GetContent(request);
        BG.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
        request.Dispose();
    }

最后的业务层代码也贴一点核心的方法:


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
 
public class ModeControl : MonoBehaviour {
 
   
    public bool IsAsync;                              //是否异步加载
    public Image BG;
    public ResourcesModeEnum ModeEnum;                //资源加载类型
    private bool Next;
    
    ResourcesLoadingMode mode = null;
    Mode_Resources resourcesMode = null;
    Mode_AssetDatabase assetDatabaseMode = null;
    Mode_WWW wwwMode = null;
    Mode_UnityWebRequest unityWebRequestMode = null;
 
 
    private int textureIndex=1;                        // 图片路径索引
 
 
    void Awake()
    {
         resourcesMode = new Mode_Resources();
         assetDatabaseMode = new Mode_AssetDatabase();
         wwwMode = new Mode_WWW();
         unityWebRequestMode = new Mode_UnityWebRequest();
    }
    
   
    private IEnumerator PreviousPageBtnClick(ResourcesModeEnum modeEnum)
    {
        changeColor = true;
        yield return new WaitForSeconds(1);
        Next = false;
        ResourceModeChoice(modeEnum);
        colorChange = true; 
        Debug.Log("----上一页按钮点击----");
    }
    private IEnumerator NextPageBtnClick(ResourcesModeEnum modeEnum)
    {
        changeColor = true;
        yield return new WaitForSeconds(1);
        Next = true;
        ResourceModeChoice(modeEnum);
        colorChange = true;
        Debug.Log("----下一页按钮点击----");
 
    }
 
    /// <summary>
    /// 资源加载方式公共方法
    /// </summary>
    /// <param name="modeEnum">资源类型</param>
    private void ResourceModeChoice(ResourcesModeEnum modeEnum)
    {    
        switch (modeEnum)
        {
            case ResourcesModeEnum.ResourcesMode:
                mode = resourcesMode;
                ChangePage();
                mode.ResourcesLoading(BG.sprite,textureIndex.ToString(), IsAsync);
                break;
            case ResourcesModeEnum.WWWMode:
                mode = wwwMode;
                ChangePage();
                StartCoroutine(Mode_WWW.WWWLoad(string.Format(@"file://{0}/{1}.jpg", Application.streamingAssetsPath, textureIndex.ToString()), WWWcallback));
                break;
            case ResourcesModeEnum.AssetDatabaseMode:
                mode = assetDatabaseMode;
                ChangePage();
                mode.ResourcesLoading(BG.sprite, string.Format("Assets/Image/{0}.jpg", textureIndex.ToString()), IsAsync);
                break;
            case ResourcesModeEnum.UnityWebMode:
                mode = unityWebRequestMode;
                ChangePage();
                StartCoroutine(Mode_UnityWebRequest.UnityWebRequestLoad(string.Format(@"file://{0}/{1}.jpg", Application.streamingAssetsPath, textureIndex), unityWebRequestcallback));
                break;
            case ResourcesModeEnum.NULL:
                mode.ResourcesUnLoading(BG.sprite);
                BG.sprite = null;
                break;
            default:
                break;
        } 
    }
 
    /// <summary>
    /// 换页公共方法
    /// </summary>
    private void ChangePage()
    {
      
        if (Next == false) textureIndex--;
        if (Next == true) textureIndex++;
        mode.Img = BG;
        mode.MB = this.GetComponent<MonoBehaviour>();
       // mode.ResourcesLoading<Sprite>(BG.sprite, IsAsync);
 
       // mode.ResourcesUnLoading(BG.sprite);
    }
    private void ResourcesClick()
    {
        ModeEnum = ResourcesModeEnum.ResourcesMode;
        ResourceModeChoice(ModeEnum);
        SetTipText(TipText,"ResourcesMode");
    }
    private void AssetBundleBtnClick()
    {
        //TODO 
    }
    private void WWWBtnClick()
    {
        if (IsAsync == false)
        {
            ModeEnum = ResourcesModeEnum.NULL;
            SetTipText(TipText, "WWW没有同步加载");
        }
        else
        {
            ModeEnum = ResourcesModeEnum.WWWMode;
            ResourceModeChoice(ModeEnum);
            SetTipText(TipText, "WWWMode");
        }
       
    }
    private void AssetDatabaseBtnClick()
    {
        if (IsAsync == false)
        {
            ModeEnum = ResourcesModeEnum.AssetDatabaseMode;
            ResourceModeChoice(ModeEnum);
            SetTipText(TipText, "AssetDatabaseMode");
        }
        else
        {
            ModeEnum = ResourcesModeEnum.NULL;
            SetTipText(TipText, "AssetDatabase没有异步加载");   
        }
       
    }
    private void UnityWebRequestBtnClick()
    {
        if (IsAsync == false)
        {
            ModeEnum = ResourcesModeEnum.NULL;
            SetTipText(TipText, "UnityWebRequest没有同步加载");
        }
        else
        {
            ModeEnum = ResourcesModeEnum.UnityWebMode;
            ResourceModeChoice(ModeEnum);
            SetTipText(TipText, "UnityWebRequestMode");
        }
      
    }
    private void SynBtnClick()
    {
        IsAsync = false;
        SetTipText(IsAnsynText, "当前为同步加载方式");
    }
    private void AsynBtnClick()
    {
        IsAsync = true;
        SetTipText(IsAnsynText, "当前为异步加载方式");
    }
 
    /// <summary>
    /// WWW回调函数
    /// </summary>
    /// <param name="obj"></param>
    private void WWWcallback(object obj)
    {
        WWW www = obj as WWW;
        Texture2D tex = www.texture;
        BG.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
        Debug.Log("----callback调用----");
        www.Dispose();
    }
 
    /// <summary>
    /// UnityWebRequest回调函数
    /// </summary>
    /// <param name="obj"></param>
    private void unityWebRequestcallback(object obj)
    {
        UnityWebRequest request = obj as UnityWebRequest;
        Texture2D tex = DownloadHandlerTexture.GetContent(request);
        BG.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
        request.Dispose();
    }
 
    private void SetTipText(Text text,string str)
    {
        text.text = str;
    }
}

这次的demo让我认识自己很多的不足,接口,类的继承,同步与异步,资源的卸载,还有很关键的一点,写的很多代码不能复用,在资源加载器写了具体的实现,这些东西应该放在上层业务层去决定你要什么资源就加载什么资源,把加载的类型和路径传进去就行了。下次千万注意,单一职责原则,可以很大的降低代码的耦合。 这只是个练习加载图片的小Demo,后面可以考虑拓展成一个通用的资源加载类。完整Demo放在了Github上,地址 https://github.com/hezhangqiang1/ResourceLoadingMode    如果这篇博客对你有点帮助,请帮忙点个Star,谢谢!
 

 

 

 

 

 

 

  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值