当前位置:   article > 正文

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

unity2d加载外部资源

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

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

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

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

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

首先是定义一个资源加载的接口:

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

然后是资源加载的基类:

  1. public class ResourcesLoadingMode : IResourcesLoadingMode
  2. {
  3. public Image Img;
  4. public MonoBehaviour MB;
  5. public virtual void ResourcesLoading<T>(T t,string path, bool IsAsync) where T:UnityEngine.Object
  6. {
  7. throw new NotImplementedException();
  8. }
  9. public virtual void ResourcesUnLoading<T>(T t) where T : UnityEngine.Object
  10. {
  11. throw new NotImplementedException();
  12. }
  13. }

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

Resouces方式:

  1. public override void ResourcesLoading<T>(T t,string path, bool IsAsync)
  2. {
  3. if (IsAsync == false)
  4. {
  5. T load = Resources.Load<T>(path);
  6. t = load;
  7. Debug.Log("===="+path+"====");
  8. if (t.GetType() == Img.sprite.GetType())
  9. {
  10. Img.sprite = t as Sprite;
  11. Resources.UnloadAsset(t);
  12. }
  13. }
  14. else
  15. {
  16. T load = Resources.LoadAsync<T>(path).asset as T;
  17. t = load;
  18. if (t.GetType() == Img.sprite.GetType())
  19. {
  20. Img.sprite = t as Sprite;
  21. Resources.UnloadAsset(t);
  22. }
  23. }
  24. }

AssetDatabase方式:

  1. public override void ResourcesLoading<T>(T t,string path, bool IsAsync)
  2. {
  3. if (IsAsync==false)
  4. {
  5. //s=string.Format( "Assets/Image/{0}.jpg",Index.ToString())
  6. T load = AssetDatabase.LoadAssetAtPath<T>(path);
  7. Debug.Log(path);
  8. t = load;
  9. Debug.Log(t.name);
  10. if (t.GetType() == Img.sprite.GetType())
  11. {
  12. Img.sprite = t as Sprite;
  13. Resources.UnloadAsset(t);
  14. }
  15. else
  16. {
  17. Debug.Log(t.name);
  18. }
  19. }
  20. else
  21. {
  22. Debug.Log("assetdatabase没有异步加载");
  23. }
  24. }

WWW方式:

  1. public override void ResourcesLoading<T>(T t,string path,bool isAsync)
  2. {
  3. if (isAsync == true)
  4. {
  5. // MB.StartCoroutine(WWWLoad());
  6. }
  7. else
  8. {
  9. Debug.Log("----WWW没有同步加载----");
  10. }
  11. }
  12. public override void ResourcesUnLoading<T>(T t)
  13. {
  14. base.ResourcesUnLoading<T>(t);
  15. }
  16. public static IEnumerator WWWLoad(string url, Action<WWW>callback)
  17. {
  18. Debug.Log("----WWW协程调用----");
  19. //string url = string.Format(@"file://{0}/{1}.jpg", Application.streamingAssetsPath, Index.ToString());
  20. WWW www = new WWW(url);
  21. yield return www;
  22. callback.Invoke(www);
  23. yield return null;
  24. }

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

  1. /// <summary>
  2. /// WWW回调函数
  3. /// </summary>
  4. /// <param name="obj"></param>
  5. private void WWWcallback(object obj)
  6. {
  7. WWW www = obj as WWW;
  8. Texture2D tex = www.texture;
  9. BG.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
  10. Debug.Log("----callback调用----");
  11. www.Dispose();
  12. }

UnityWebRequest方式:

  1. public override void ResourcesLoading<T>(T t,string path,bool isAsync)
  2. {
  3. if (isAsync==false)
  4. {
  5. Debug.Log("unityWebRequest没有同步加载");
  6. }
  7. }
  8. public override void ResourcesUnLoading<T>(T t)
  9. {
  10. base.ResourcesUnLoading<T>(t);
  11. }
  12. public static IEnumerator UnityWebRequestLoad(string url,Action<UnityWebRequest>callback)
  13. {
  14. //string url =string.Format( @"file://{0}/{1}.jpg", Application.streamingAssetsPath,Index.ToString());
  15. UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture(url);
  16. yield return webRequest.SendWebRequest();
  17. if (webRequest.isNetworkError || webRequest.isHttpError)
  18. {
  19. Debug.Log(webRequest.error);
  20. }
  21. else
  22. {
  23. callback.Invoke(webRequest);
  24. yield return null;
  25. //Texture2D tex = DownloadHandlerTexture.GetContent(webRequest);
  26. //Img.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
  27. }
  28. }
  29. }

UnityWebRequest的回调:

  1. /// <summary>
  2. /// UnityWebRequest回调函数
  3. /// </summary>
  4. /// <param name="obj"></param>
  5. private void unityWebRequestcallback(object obj)
  6. {
  7. UnityWebRequest request = obj as UnityWebRequest;
  8. Texture2D tex = DownloadHandlerTexture.GetContent(request);
  9. BG.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
  10. request.Dispose();
  11. }

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

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Networking;
  5. using UnityEngine.UI;
  6. public class ModeControl : MonoBehaviour {
  7. public bool IsAsync; //是否异步加载
  8. public Image BG;
  9. public ResourcesModeEnum ModeEnum; //资源加载类型
  10. private bool Next;
  11. ResourcesLoadingMode mode = null;
  12. Mode_Resources resourcesMode = null;
  13. Mode_AssetDatabase assetDatabaseMode = null;
  14. Mode_WWW wwwMode = null;
  15. Mode_UnityWebRequest unityWebRequestMode = null;
  16. private int textureIndex=1; // 图片路径索引
  17. void Awake()
  18. {
  19. resourcesMode = new Mode_Resources();
  20. assetDatabaseMode = new Mode_AssetDatabase();
  21. wwwMode = new Mode_WWW();
  22. unityWebRequestMode = new Mode_UnityWebRequest();
  23. }
  24. private IEnumerator PreviousPageBtnClick(ResourcesModeEnum modeEnum)
  25. {
  26. changeColor = true;
  27. yield return new WaitForSeconds(1);
  28. Next = false;
  29. ResourceModeChoice(modeEnum);
  30. colorChange = true;
  31. Debug.Log("----上一页按钮点击----");
  32. }
  33. private IEnumerator NextPageBtnClick(ResourcesModeEnum modeEnum)
  34. {
  35. changeColor = true;
  36. yield return new WaitForSeconds(1);
  37. Next = true;
  38. ResourceModeChoice(modeEnum);
  39. colorChange = true;
  40. Debug.Log("----下一页按钮点击----");
  41. }
  42. /// <summary>
  43. /// 资源加载方式公共方法
  44. /// </summary>
  45. /// <param name="modeEnum">资源类型</param>
  46. private void ResourceModeChoice(ResourcesModeEnum modeEnum)
  47. {
  48. switch (modeEnum)
  49. {
  50. case ResourcesModeEnum.ResourcesMode:
  51. mode = resourcesMode;
  52. ChangePage();
  53. mode.ResourcesLoading(BG.sprite,textureIndex.ToString(), IsAsync);
  54. break;
  55. case ResourcesModeEnum.WWWMode:
  56. mode = wwwMode;
  57. ChangePage();
  58. StartCoroutine(Mode_WWW.WWWLoad(string.Format(@"file://{0}/{1}.jpg", Application.streamingAssetsPath, textureIndex.ToString()), WWWcallback));
  59. break;
  60. case ResourcesModeEnum.AssetDatabaseMode:
  61. mode = assetDatabaseMode;
  62. ChangePage();
  63. mode.ResourcesLoading(BG.sprite, string.Format("Assets/Image/{0}.jpg", textureIndex.ToString()), IsAsync);
  64. break;
  65. case ResourcesModeEnum.UnityWebMode:
  66. mode = unityWebRequestMode;
  67. ChangePage();
  68. StartCoroutine(Mode_UnityWebRequest.UnityWebRequestLoad(string.Format(@"file://{0}/{1}.jpg", Application.streamingAssetsPath, textureIndex), unityWebRequestcallback));
  69. break;
  70. case ResourcesModeEnum.NULL:
  71. mode.ResourcesUnLoading(BG.sprite);
  72. BG.sprite = null;
  73. break;
  74. default:
  75. break;
  76. }
  77. }
  78. /// <summary>
  79. /// 换页公共方法
  80. /// </summary>
  81. private void ChangePage()
  82. {
  83. if (Next == false) textureIndex--;
  84. if (Next == true) textureIndex++;
  85. mode.Img = BG;
  86. mode.MB = this.GetComponent<MonoBehaviour>();
  87. // mode.ResourcesLoading<Sprite>(BG.sprite, IsAsync);
  88. // mode.ResourcesUnLoading(BG.sprite);
  89. }
  90. private void ResourcesClick()
  91. {
  92. ModeEnum = ResourcesModeEnum.ResourcesMode;
  93. ResourceModeChoice(ModeEnum);
  94. SetTipText(TipText,"ResourcesMode");
  95. }
  96. private void AssetBundleBtnClick()
  97. {
  98. //TODO
  99. }
  100. private void WWWBtnClick()
  101. {
  102. if (IsAsync == false)
  103. {
  104. ModeEnum = ResourcesModeEnum.NULL;
  105. SetTipText(TipText, "WWW没有同步加载");
  106. }
  107. else
  108. {
  109. ModeEnum = ResourcesModeEnum.WWWMode;
  110. ResourceModeChoice(ModeEnum);
  111. SetTipText(TipText, "WWWMode");
  112. }
  113. }
  114. private void AssetDatabaseBtnClick()
  115. {
  116. if (IsAsync == false)
  117. {
  118. ModeEnum = ResourcesModeEnum.AssetDatabaseMode;
  119. ResourceModeChoice(ModeEnum);
  120. SetTipText(TipText, "AssetDatabaseMode");
  121. }
  122. else
  123. {
  124. ModeEnum = ResourcesModeEnum.NULL;
  125. SetTipText(TipText, "AssetDatabase没有异步加载");
  126. }
  127. }
  128. private void UnityWebRequestBtnClick()
  129. {
  130. if (IsAsync == false)
  131. {
  132. ModeEnum = ResourcesModeEnum.NULL;
  133. SetTipText(TipText, "UnityWebRequest没有同步加载");
  134. }
  135. else
  136. {
  137. ModeEnum = ResourcesModeEnum.UnityWebMode;
  138. ResourceModeChoice(ModeEnum);
  139. SetTipText(TipText, "UnityWebRequestMode");
  140. }
  141. }
  142. private void SynBtnClick()
  143. {
  144. IsAsync = false;
  145. SetTipText(IsAnsynText, "当前为同步加载方式");
  146. }
  147. private void AsynBtnClick()
  148. {
  149. IsAsync = true;
  150. SetTipText(IsAnsynText, "当前为异步加载方式");
  151. }
  152. /// <summary>
  153. /// WWW回调函数
  154. /// </summary>
  155. /// <param name="obj"></param>
  156. private void WWWcallback(object obj)
  157. {
  158. WWW www = obj as WWW;
  159. Texture2D tex = www.texture;
  160. BG.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
  161. Debug.Log("----callback调用----");
  162. www.Dispose();
  163. }
  164. /// <summary>
  165. /// UnityWebRequest回调函数
  166. /// </summary>
  167. /// <param name="obj"></param>
  168. private void unityWebRequestcallback(object obj)
  169. {
  170. UnityWebRequest request = obj as UnityWebRequest;
  171. Texture2D tex = DownloadHandlerTexture.GetContent(request);
  172. BG.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
  173. request.Dispose();
  174. }
  175. private void SetTipText(Text text,string str)
  176. {
  177. text.text = str;
  178. }
  179. }

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/125142
推荐阅读
相关标签
  

闽ICP备14008679号