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,谢谢!

原文链接:https://blog.csdn.net/qq_35711014/article/details/89891139?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165277103516782395321147%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165277103516782395321147&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-27-89891139-null-null.nonecase&utm_term=%E8%B5%84%E6%BA%90

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
文明发言,共建和谐米科社区
提交
头像

昵称

取消
昵称表情图片