找回密码
 立即注册
查看: 453|回复: 0

Unity AssetBundle 资源打包,加载,本地缓存方式,安卓,PC本地加载路径问题

[复制链接]
发表于 2021-2-24 13:17 | 显示全部楼层 |阅读模式
AssetBundle的定义和作用:
          1,AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至整个场景,可以在游戏运行的时候被加载。
           2,AssetBundle自身保存着互相的依赖关系。
           3,压缩包可以使用LZMA和LZ4压缩算法,减少包大小,更快的进行网络传输。
           4,把一些可以下载内容放在AssetBundle里面,可以减少安装包的大小。
AssetBundle使用流程(打包方法):
            1,首先要选中需要打包的资源在Inspector面板最下方指定这个资源的AssetBundle属性(包名和后缀),注意这里的名字和后缀是不区分大小写的,如下图:
              2,构建AssetBundle,这里需要用到编辑器扩展技术,我把资源打包在了StreamingAssets目录下,这是一个Assets下的特殊目录,StreamingAssets也就是流式资源载入目录,该目录被拷贝到build文件夹中,不会修改,一般用于放置音频文件。代码如下:
  1. public class CreateAssetBundles
  2. {
  3.     [MenuItem("Tools/Build AssetBundle")]
  4.     static void CreateAssetBundle()
  5.     {
  6.         string path = "Assets/StreamingAssets";
  7.         if(Directory.Exists(path) == false)//判断这个文件夹存不存在
  8.         {
  9.             Directory.CreateDirectory(path);
  10.         }
  11.         BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.Android);
  12.     }
  13. }
复制代码
           3,在编辑器下面打包出来的AB包可以放在本地上,也可以放在服务器上加载。


AssetBundle资源的加载(本地加载,服务器下载):
           1,本地同步加载AssetBundle包并且获取包的内容方式,AssetBundle.LoadFromFile(string path),从磁盘上的文件同步加载AssetBundle,代码如下:
  1. private void LoadFromFile(string path)
  2.     {
  3.       
  4.         //传入这个AB包存在本地的路径加载本地资源
  5.         AssetBundle ab = AssetBundle.LoadFromFile(path);
  6.         //获取可使用AssetBundle这个类里面的LoadAsset<T>(string name)方法获取资源
  7.         GameObject wallPrefab = ab.LoadAsset<GameObject>("CubeWall");
  8.         Instantiate(wallPrefab);//实例化这个游戏物体
  9.     }
复制代码

               2,本地异步加载AssetBundle包并且获取包的内容方式,AssetBundle.LoadFromMemoryAsync(byte[] bytes),代码如下:
  1. IEnumerator LoadFromMemoryAsync(string path)
  2.     {
  3.       
  4.         //打开二进制数组文件,并将打开的数据传进去
  5.         AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
  6.         yield return createRequest;//等待加载时间
  7.         AssetBundle ab = createRequest.assetBundle;//获取加载出来的东西
  8.         GameObject prefab = ab.LoadAsset< GameObject > ("CubeWall");
  9.         Instantiate(prefab);
  10.     }
复制代码

              3,下面代码是异步加载的一个变形同步加载,AssetBundle.LoadFromMemory(byte[] bytes),他的作用有很多,下文会说到
  1. private void LoadFromMemory(string path)
  2.     {
  3.         //异步加载的一个变形同步加载,传入具有AssetBundle数据的字节数组
  4.         AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes(path));
  5.         GameObject wallPrefab = ab.LoadAsset<GameObject>("CubeWall");//获取这个名字的游戏物体
  6.         Instantiate(wallPrefab);//实例化这个游戏物体
  7.     }
复制代码
4,使用UnityWebRequestAssetBundle.GetAssetBundle(string uri)到服务器下载AB包,现在官方推荐的主流方式,以前使用的WWW方式下载,还有UnityWebRequest.GetAssetBundle(string uri)这两种方式都已经弃用了;使用这个方式不但可以下载服务器上的资源,同时他也可以加载本地的资源,但是强烈建议如果要加载本地资源,还是使用本地同步/异步加载的方式比较妥当,两种方式下面代码都有写到,留意代码注释:
  1. IEnumerator MyUnityWebRequest()
  2.     {
  3.         //本地加载路径前面要加上file://否则会出错
  4.         //string uri = @"file://D:\Unity3D_Project\Advanced\Asset Bundle Project\AssetBundles\cubewall.unity3d";
  5.         //UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri);
  6.         //服务器上下载
  7.         UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle("http://localhost/AssetBundles/cubewall.unity3d");
  8.         yield return request.SendWebRequest();
  9.         if (string.IsNullOrEmpty(request.error) == false)//判断下载有没有出错,request.error表示错误信息
  10.         {
  11.             Debug.Log(request.error);//输出错误
  12.             yield break;//退出携程
  13.         }
  14.         //AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);//获取下载到的资源
  15.         //获取资源的另外一种方式,直接获取到UnityWebRequest下载到的东西然后强转成DownloadHandlerAssetBundle,然后再获取到AssetBundle
  16.         AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
  17.         GameObject prefab = ab.LoadAsset<GameObject>("CubeWall");
  18.         Instantiate(prefab);
  19. }
复制代码

减少包大小打包方式:我们可以将一些共用的图片/材质单独打包成一个包,这样做可以大大的减小AB包的大小,因为我们在打包的时候系统或默认将这个包的依赖一起打包进去的,当我们打包的A包和B包都依赖同一个材质/图片时那么系统就会默认的将这个依赖同时打包到A包和B包里,这样就会导致我们打包出来的AB包比较大,但当我们将A包和B包的依赖单独打包成一个包时,这时系统就不会再将这个依赖打包到两个包里了,这样我们的包就会小很多,不过当我们要用到包的资源,在加载包的资源之前,先把这个包的依赖加载出来,加载包的依赖的,代码如下:(这里加载依赖的时候需要注意的是我们要加载的是跟文件目录名字一样的后缀为manifest包,比如我们上面构造AB包的时候是直接在Asset文件下创建了StreamingAssets将打包出来的包放在StreamingAssets这个文件夹下,那么我们加载的依赖包就是StreamingAssets.manifest这个包)
  1.         //加载这个物体的依赖
  2.         //加载生成AB包文件时系统自动生成的一个名字跟文件目录一样的后缀为manifest包
  3.         AssetBundle manifestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
  4.         //获取到他的AssetBundleManifest文件
  5.         AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
  6.         string[] strs = manifest.GetAllDependencies("cubewall.unity3d");//获取到传进去的包的所有依赖的包的名字
  7.         //遍历并加载所有依赖的包
  8.         foreach (string name in strs)
  9.         {
  10.             //加载依赖,将文件的根目录(我们打包出来的包的保存路径)+包名(即我们自己定义的AssetBundle打包的名字和后缀)传进去
  11.             AssetBundle.LoadFromFile(rootDirectory + name);
  12.         }
复制代码
如何将从服务器上下载回来的AB包保存到本地上,代码如下:
1,要获取到服务器上下载回来的数据,需要用到UnityWebRequest.Get(string uri) 这个API去下载,只有使用这个API下载回来的资源我们才是可以访问到数据的,官方有一个专门用于下载AB包的API UnityWebRequestAssetBundle.GetAssetBundle(string uri)使用这个API下载回来的资源它是不支持原始数据访问的,也就是说我们想要保存从服务器上下载回来的AB包资源就不能使用这个API了,从服务器上下载AB包并保存到本地的代码如下:
  1. //获取服务器上的资源
  2.     IEnumerator MyUnityWebRequest()
  3.     {
  4.         string uri = "http://localhost/AssetBundles/res.ab";//服务器地址
  5.         request = UnityWebRequest.Get(uri);//要使用这种方式获取资源,才能访问到他的字节流
  6.         //这个方法主要是用来获取AssetBundle资源的,但他下载到的数据是不给访问的,如果想访问或者保存下载回来的数据用上面的UnityWebRequest.Get()
  7.         //request = UnityWebRequestAssetBundle.GetAssetBundle(pathMP);
  8.         yield return request.SendWebRequest();
  9.         
  10.          //保存下载回来的文件
  11.         if (request.isDone)
  12.         {
  13.             //构造文件流
  14.            FileStream fs = File.Create(Application.persistentDataPath + "/res.ab");
  15.             //将字节流写入文件里,request.downloadHandler.data可以获取到下载资源的字节流
  16.            fs.Write(request.downloadHandler.data, 0, request.downloadHandler.data.Length);
  17.            fs.Flush();     //文件写入存储到硬盘
  18.            fs.Close();     //关闭文件流对象
  19.            fs.Dispose();   //销毁文件对象
  20.         }
  21.         //这里我们直接使用异步加载的一个变形同步加载,获取下载回来的资源
  22.         ab = AssetBundle.LoadFromMemory(request.downloadHandler.data);
  23.         //ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
  24.     }
复制代码

          2,从服务器下载回来的数据并保存在本地后,如何加载保存在本地的数据,方式有很多种,可以用到上面介绍的,同步加载方式;异步加载方式;或者是异步加载的变形同步加载都可以主要看需求的,我这里使用了官方推荐的专门获取AB包的API来加载,代码如下:
  1. IEnumerator MyData()
  2.     {
  3.         //加载保存在本地的资源
  4.         request = UnityWebRequestAssetBundle.GetAssetBundle(Application.persistentDataPath + "/res.ab");
  5.         yield return request.SendWebRequest();
  6.         ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
  7.       
  8.     }
复制代码

把打包好的AB包直接放在本地上StreamingAssets文件夹下,在进入游戏后直接从本地进行加载的路径问题(PC端与安卓端的路径)
          1,为什么要放在StreamingAssets这个文件夹下来加载呢,因为该目录会被拷贝到
build文件夹中,不会修改,他是流式资源载入目录,而且官方也专门给我们封装了加载路径
          2,加载StreamingAssets这个文件夹下的资源的路径是:
Application.streamingAssetsPath+"/"+文件名称组成,这里需要加载的资源要带后缀
这个路径的真实路径在PC端和安卓端都是不同的,Unity会根据发布的平台而进行变动,
值得一提的是在Unity旧版本里面发布安卓端,使用这个路径加载StreamingAssets
下的资源他是会报错的,但是现在新版本(2019版)经过实验是不会出现任何问题的不管
是PC端还是安卓端加载都没有任何问题,如果你的版本是旧版本或者是在安卓端加载时
路径出现问题,那么可以使用:
"jar:file://" + Application.dataPath + "!/assets/"+文件名称组成  这个路径,这个路径
是旧版本安卓端加载StreamingAssets文件夹下资源的路径。


加载AssetBundle  资源,运行游戏时出现材质丢失问题解决方法:
1,我们在打包AB包的时候,Unity默认是不连Shader一同打包进去的,所以当我们在
发布运行的时候就会出现材质丢失的问题,所以这个时候就需要我们自行添加了,添加步骤如
下:点击Edit>Project Settings>Graphics,然后下拉到Always Included Shaders,
将Size改大一些,然后在将丢失的那个材质所使用的Shader添加进去,然后再重新打包运
行就可解决材质丢失的问题。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-20 14:47 , Processed in 0.090382 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表