当前位置:   article > 正文

Unity Asset Bundle 基础_unity bundle asset

unity bundle asset

Asset Bundle 基础

一· 给资源上标签

要将资源打包成一个asset bundle之前要给对应资源添加asset bundle标签。一般标签创建规则为:文件名+unity3d/ab/assetbundle 后缀。资源有了标签之后,等会我们在代码中调用打AB包的API时,unity就会在整个项目资源文件里面查找拥有标签需要打包的文件,并根据标签打出ab包。注意:Resources/StreamingAssets 文件夹中的内容不会被Unity打包。

二· 用代码进行打包

对AB包的操作主要用到的是在UnityEditor里面的API。创建则主要是BuildPipeline 这个类。这个方法有很多重载,这里我们用比较简单的一种来进行尝试:

[MenuItem("Assets/Build All AssetBundles)]
private static void BuildAll()
{
		BuildPipeline.BuildAssetBundles();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

首先,顺便复习一下MenuItem这个特性吧。它的作用是能够把拥有该特性的静态 方法(千万注意必须是静态方法)添加到Unity窗口上端的菜单栏里头。根据你传入的字符串在对应的位置创建出该方法的点击按钮,可以让你通过点击触发该方法。
然后就会看到这个效果效果图
然后,我们点击这个方法,如果没有意外就会开始读条打包啦。要注意的是,我这里填写的是相对路径:“AssetBundles”。即会在这个项目根目录下为根节点,往后查找路径。同时,别忘了要保证填写的文件夹已经存在于对应路径中,因为这个方法是不会自动帮你创建的。如果不存在该文件夹就会报“错误路径”之类的错误。为了保险起见,也可以在代码中用IO里面的Directory类去判定一下路径的准确性,并作出对应的处理(比如如果查无此文件夹,则用IO去创建一个该文件夹,保证路径的正确性)。

打包中的技巧和注意事项:
  1. 在给资源添加打包标签的时候,比如我们刚刚的那个Wall资源,我是直接就起了个标签名为wall 和 unity3d的后缀。一个技巧就是这个标签名字也可以创建文件夹。比如我们可以给这个Wall资源起标签名为:test/wall。等你打出包的时候你会发现,原本应该直接放在AssetBundles文件夹下的wall.unity3d,被放到了一个新创建出来的文件夹里面,路径是AssetBundles/test/wall.unity3d。
  2. 依赖打包 :在我们打包预制体的时候,其中所用到的依赖(比如,贴图,材质等)也会一同被打包进去,在运行时会被加载进去。假设现在有两个预设体共同用到一套依赖,比如一个球型和一个矩形的预设,他们都用到了同样的材质球。如果我们把他们共同依赖的材质球和贴图打包,那么我们分别打包这两个预设体的时候他们就不会再分别把这个材质球和贴图打到他们的包中。这样就可以大大减少打包的大小(说的很多其实简单来说就是要把几个预制体公用的资源一起单独打一个包,这样就可以避免每个预制体打包的时候还会各自打一次那些资源)。
  3. 如果使用了依赖打包,别忘了要也把被依赖的资源加载到内存,这样你加载对应需要的资源时候,才不会造成材质丢失。

加载AB包

1. 加载本地AB包

本地加载的话,可以直接使用AssetBundle类中的LoadFromFile方法:

private void LoadLocalAB()
{
		AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/scene/wall.unity3d");
		//指定名字一个一个加载:注意这里填的是你场景中创建的预设体的名字,不是包名
		GameObject wallPrefab = ab.LoadAsset<GameObject>("Floor");
		Instantiate(wallPrefab);
		//也可以一次性load所有的资源
		Object[] objs = ab.LoadAllAssets();
		foreach(Object o in objes)
		{
				Instantiate(o);
		}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

也可以使用AssetBundle.LoadFromMemoryAsync,这里直接上官方代码了:

IEnumerator LoadFromMemoryAsync(string path)
{
		AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
		yield return createRequest;
		AssetBundle bundle = createRequest.assetBundle;
		var prefab = bundle.LoadAsset<GameObject>("MyObject");
		Instantiate(prefab);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
2. 从服务器下载AB包

从官方下载可以用WWW.LoadFromCacheOrDownload或者UnityWebRequest去做。这里我只记录UnityWebRequest。

再次懒惰的搬运一下官网的代码:

IEnumerator InstantiateObject()
{
		string uri = "file:///"+Application.dataPath+"/AssetBundles/"+assetBundleName;
		UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri,0);
		//在调用requet.Send()之后才真正开始向服务器发起了请求
		yield return request.Send();
		AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
		//这里还有另外一种方法送request 里面获取到加载的AssetBundle
		//AssetBundle bundle = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
		GameObject cube = bundle.LoadAsset<GameObject>("Cube");
		GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");
		Instantiate(cube);
		Instantiate(sprite);
		//这里如果需要把加载到的内容保存到本地硬盘,可以参考以下代码:这里的path为想保存到的路径
		//File.WriteAllBytes(path, request.downloadHandler.data);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
3 . 加载Manifest文件获取依赖关系

上面打包的时候有说过依赖打包,为了避免资源丢失(比如材质,贴图等),我们就需要加载使用某个AB包的时候,把它依赖的资源包也加载出来。因此,获取到包与包之间依赖关系就有意义了。而打包时候生成的manifest文件就保存着这个信息。我们可以在加载的时候也把当前保存这些AB包的文件夹的manifest文件加载出来从而获得总的依赖关系。

代码如下,同样来自官方文档:

AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestPath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("ManifestName");
string [] dependencies = manifest.GetAllDependencies("assetBundle"); //这里传入你想获取依赖关系的AB包包名
//然后根据依赖关系,一一对应先把依赖资源包加载进来
foreach(string dependency in dependencies)
{
		//因为这些依赖资源只需要加载就可以了,所以我们不需要保存返回值
		AssetBundle.LoadFromFile(Path.Combine(assetBundlePath,dependency));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

三. 卸载资源(从内存中清楚)

有加载自然就有卸载。将不用的包从内存中清楚的作用这里就不赘述的。卸载主要是通过AssetBundle自带的一个方法——Unload()。需要传一个bool指来指定是否卸载正在使用中的资源。

AssetBundle.Unload(true);  //传入true的时候,无视包中是否有资源正在被使用,全部卸载掉
AssetBundle.Unload(false); //false时,只会卸载掉包中没有正在被使用的资源;仍有引用的资源会被保留
  • 1
  • 2

另外,如果想卸载残留的资源。但是此时之前的那些包又已经被卸载过了,这时候就可以用Resources.UnloadUnusedAssets。不过务必保证在场景中和代码中没有对这些资源的引用。非叠加性的场景切换也会自动调用这个方法去卸载残留的无用资源。

四. 使用AB包的一些常见问题及优化

1. 依赖资源重复打包

这个问题我觉得前面已经说得比较详细了。这里稍微再总结一下:资源如果同时被多个包依赖,那在没有把这些共享资源单独打成一个包的情况下,每一个依赖于这个资源的AB包都会把这个被依赖的资源打一份给自己,因此就造成了重复打包。

解决方法之一就是把共享资源单独打一个包出来。

2. 图集重复

Unity会在打包的时候自动把图片资源打进一个图集里面。如果有资源依赖于这个图集的其中一个图片,那个AB包就会把整个图集打包一份进去,造成该图集被重复打包。

解决方法就是在手动把每张图片的Packing Tag参数设置一下,保证共享的图片打成一个AB包。有点类似依赖资源重复打包的解决思路(Packing Tag 参数在图片Inspector中,注意把图片格式设成Sprite)。

五.最后

Unity 官方有在他们GitHub上放了一个AssetBundle的浏览工具。大家有兴趣的可以自行去搜索一下,叫做Asset Bundle Browser tool.

希望这篇文章能够帮到各位的复习和基础的巩固。谢谢阅读!

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

闽ICP备14008679号