当前位置:   article > 正文

AssetBundle动态加载Scene场景_assetbundle中加载场景

assetbundle中加载场景

加载场景有两种方法,一种是常规的build settings添加scene,一种是通过AssetBundle加载Scene。

  1. using UnityEngine;
  2. using UnityEngine.SceneManagement;
  3. public class SceneTest : MonoBehaviour
  4. {
  5. void Start()
  6. {
  7. SceneManager.LoadSceneAsync("xxx1", LoadSceneMode.Additive);
  8. SceneManager.LoadSceneAsync("xxx2", LoadSceneMode.Additive);
  9. SceneManager.LoadSceneAsync("xxx3", LoadSceneMode.Additive);
  10. }
  11. }

 上面是标准的异步加载场景,如果不在build settings中添加场景,直接加载scene,就会报下面的错。

因此对于需要热更新的项目,如果场景.unity资源变更了,无法在build settings中重新设置,只能用Assetbundle加载场景。 

下面是打ab包的工具(BuildAssetBundleTool放到Scripts/Editor文件夹下)和标准化路径工具。

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEditor;
  5. using System.IO;
  6. /// <summary>
  7. /// 构建工具类:
  8. /// 创建了三种构建方法windows android ios。
  9. /// Build方法:从所有路径查找文件,排除meta后,把每个文件名作为被打包资源名和bundle名(当然一个bundle可以打包多个文件)
  10. /// </summary>
  11. public class BuildAssetBundleTool : Editor
  12. {
  13. //如何使用Build呢,直接添加工具栏
  14. [MenuItem("Tools/Build Windows Bundle")]
  15. static void BundleWindowsBuild()
  16. {
  17. Build(BuildTarget.StandaloneWindows);
  18. }
  19. //如何使用Build呢,直接添加工具栏
  20. [MenuItem("Tools/Build Android Bundle")]
  21. static void BundleAndroidBuild()
  22. {
  23. Build(BuildTarget.Android);
  24. }
  25. //如何使用Build呢,直接添加工具栏
  26. [MenuItem("Tools/Build IOS Bundle")]
  27. static void BundleIOSBuild()
  28. {
  29. Build(BuildTarget.iOS);
  30. }
  31. //为了能够构建多平台,需要把目标平台作为参数传入。
  32. static void Build(BuildTarget target)
  33. {
  34. //主要目的是收集这个build信息,需要打哪些文件,需要给bundle包用一个什么样的名字,BuildAssetBundles函数用到这个Build数组
  35. List<AssetBundleBuild> assetBundleBuilds = new List<AssetBundleBuild>();
  36. //第一步搜索出我们这个所有文件的文件名Directory.GetDirectories和Directory.GetFiles对应两种打包策略一个获取文件夹一个获取文件,GetFiles比较简单
  37. //searchPattern通配符,*是默认 https://www.cnblogs.com/ost/archive/2006/08/20/481625.html
  38. string[] files = Directory.GetFiles(PathUtil.BuildResourcesPath, "*", SearchOption.AllDirectories);
  39. //所有文件都找出来了,需要排除调meta文件
  40. for (int i = 0; i < files.Length; i++)
  41. {
  42. if (files[i].EndsWith(".meta"))
  43. {
  44. continue;
  45. }
  46. //创建一个需要build的Bundle
  47. AssetBundleBuild assetBundle = new AssetBundleBuild();
  48. //处理出来的路径斜杠可能不同。需要规范一下
  49. string fileName = PathUtil.GetStandardPath(files[i]);
  50. string assetName = PathUtil.GetUnityPath(fileName);//获取unity相对路径
  51. //一个assetBundle可以打包多个文件,这里只放一个文件
  52. assetBundle.assetNames = new string[] { assetName };//assetBundle是一个相对路径文件名
  53. //创建包名
  54. string bundleName = fileName.Replace(PathUtil.BuildResourcesPath, "").ToLower();
  55. assetBundle.assetBundleName = bundleName + ".ab";//Bundle需要后缀是.ab,,,,,,,,至此,Bundle的信息收集完了,需要放进list
  56. assetBundleBuilds.Add(assetBundle);
  57. }
  58. //为什么不用另一个重载BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform),是因为需要自己去资源设置bundle名打标签,很麻烦
  59. //第二个参数把list转为array数组
  60. //第三个参数是压缩格式,选择默认
  61. //第四个参数是目标平台,先选择win
  62. if(Directory.Exists(PathUtil.BundleOutPath))
  63. {
  64. //判断是否有路径,如果有这个文件夹,就删掉文件,,递归recursive删掉所有文件和子文件。
  65. Directory.Delete(PathUtil.BundleOutPath, true);
  66. }
  67. Directory.CreateDirectory(PathUtil.BundleOutPath);//删除路径后,创建路径
  68. BuildPipeline.BuildAssetBundles(PathUtil.BundleOutPath, assetBundleBuilds.ToArray(), BuildAssetBundleOptions.None, target);
  69. }
  70. }
  1. /// <summary>
  2. /// 路径工具类:
  3. /// 1定义了所有用到的路径
  4. /// 2返回标准路径或返回unity下的几个文件夹的相对路径
  5. /// </summary>
  6. //因为所有路径都要用到,所以写入一个只读变量中,用来后期访问
  7. public class PathUtil
  8. {
  9. //为什么要把Application定义出来,因为每一次访问都需要GC一次,定义出来就访问一次;
  10. public static readonly string AssetPath = Application.dataPath;
  11. //只读的,需要打Bundle的目录
  12. public static readonly string BuildResourcesPath = AssetPath + "/BuildResources/";
  13. //Bundle输出目录
  14. public static readonly string BundleOutPath = Application.streamingAssetsPath;
  15. /// <summary>
  16. /// 获取Unity的相对路径
  17. /// </summary>
  18. /// <param name="path">绝对路径</param>
  19. /// <returns></returns>
  20. public static string GetUnityPath(string path)
  21. {
  22. if(string.IsNullOrEmpty(path))
  23. {
  24. return string.Empty;
  25. }
  26. //从Assets位置拿到相对目录
  27. return path.Substring(path.IndexOf("Assets"));
  28. }
  29. /// <summary>
  30. /// 获取标准路径
  31. /// </summary>
  32. /// <param name="path">路径</param>
  33. /// <returns></returns>
  34. public static string GetStandardPath(string path)
  35. {
  36. if (string.IsNullOrEmpty(path))
  37. {
  38. return string.Empty;
  39. }
  40. //先处理空格,在处理反斜杠
  41. return path.Trim().Replace("\\", "/");
  42. }
  43. }

这两个工具放到文件夹后,在unity工具栏的位置出现Editor新工具,选择第一个构建Bundle,就可以把创建好的场景打包到StreamingAssets路径下,,,在SceneTest中通过这个路径,加载AssetBundle包,就可以动态加载场景了。

 重新编写SceneTest场景加载的脚本,挂到起始场景的任意物体上,就可以动态加载场景了。

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.SceneManagement;
  5. public class sceneTest : MonoBehaviour
  6. {
  7. // Start is called before the first frame update
  8. IEnumerator Start()
  9. {
  10. yield return LoadSceneAB("xxx1");
  11. yield return LoadSceneAB("xxx2");
  12. yield return LoadSceneAB("xxx3");
  13. }
  14. IEnumerator LoadSceneAB(string sceneName)
  15. {
  16. string assetBundleName = "scenes/" + sceneName +".unity.ab";
  17. string path = Application.dataPath + "/StreamingAssets/" + assetBundleName;
  18. AssetBundleCreateRequest myLoadedAssetBundle = AssetBundle.LoadFromFileAsync(path);
  19. yield return myLoadedAssetBundle;
  20. if (myLoadedAssetBundle != null)
  21. {
  22. SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
  23. }
  24. }
  25. }

 运行前后

 如果该场景中依赖于其他物体、材质等,也是通过打包才能获取的,那么需要将其他物体也通过AssetBundle获取,获取方法需要编写一个依赖文件,说明此资源依赖于哪些资源,并通过递归的方法,加载这些依赖资源的ab包,下次再写这个地方的实现。

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

闽ICP备14008679号