Unity中AssetBundle的打包和加载
发表于2018-09-29
在Unity中,实现物体动态加载的方法主要包括了Resources.Load()和AssetBundle两种。当我们的游戏资源需要热更新时,AssetBundle一定会是所有开发人员的首选。
Unity官方提供了十分方便的打包工具Asset Bundle Browser,同时该工具也作为开源项目放到了GitHub上。通过Window->AssetBundle Browser便可打开该工具进行相关操作。我们只需将需要打包的内容拖拽到工具中便会生成相应的Bundle。如果我们同时打多个Bundle,如果Bundle中出现了重复的资源,该工具也会在旁边以黄色的小叹号给我们提示,这样我们便可以将重复的资源单独打包,从而让我们的Bundle运行更高效。
在命名Bundle的过程中,如果我们不手动添加.assetbundle后缀的话,打包出来的文件也不存在该后缀,当我们为AssetBundle添加后缀后打包出来的bundle文件也会自动包含该后缀名称(该后缀名称主要取决于我们的文件服务器可以下载的文件类型,只有可以下载的文件才能通过Unity的WWW方法加载出来,否则将会报错。如果要修改文件服务器中的下载类型,只需修改服务器中的配置文件web.config文件中的MIME属性便可。)
<configuration> <system.webServer> <staticContent> <mimeMap fileExtension="." mimeType="application/File" /> <mimeMap fileExtension=".assetbundle" mimeType="unity3d/assetbundle" /> </staticContent> </system.webServer> </configuration>
如上所示,fileExtension=”.”表示可以下载无后缀的文件,当我们设置fileExtention=”.assetbundle”时,则表示可以下载后缀名为。assetbundle的文件。
我们打包的assetbundle文件,除了。assetbundle文件外,还包含了manifest文件。同时除了我们已经命名的文件外,还包含了一个则外的assetbundle文件和manifest文件,这两个文件中包含了我们此次打包的所有资源信息。其中Manifest文件信息如下所示:
ManifestFileVersion: 0 CRC: 3392523828 AssetBundleManifest: AssetBundleInfos: Info_0: Name: overlookpointparent.assetbundle Dependencies: {} Info_1: Name: dotweenpathparent.assetbundle Dependencies: {} Info_2: Name: props.assetbundle Dependencies: {}
Manifest文件中包含了我们打包的Bundle中的信息。我们在加载Bundle时一般不会加载Manifest文件,我们可以通过包含所有Bundle信息的文件来动态获取每一个Bundle的信息。
在Unity中,加载Bundle的方式主要通过WWW来实现
WWW www = new WWW(URL); WWW www = WWW.LoadFromCacheOrDownload(URL,hash);
上述方法中,第一种在每次执行时都会从给定地址中获取相应的文件并加载,如果是在服务器的文件,则需要用户每次都进行下载,用户体验不会很好,第二种方式则会先对缓存目录进行判断,如果当前缓存的Bundle与给定地址的Bundle版本一致,则直接加载缓存中的文件,根据Hash值判断如果不一致,则需要重新下载之后再加载。
那么我们如何获取每一个Bundle的Hash值呢,这就用到了我们上边提到的Manifest文件。在Manifest文件中保存了所有Bundle的Hash值。
我们不能直接加载Manifest文件来获取,需要通过那个包含所有Bundle信息的Bundle文件来获取Manifest信息。我们可以每次都通过new WWW(URL)来下载占用较小空间但包含全部Bundle信息的文件来获取Hash值,通过判断Hash值来动态加载其他占用空间较大的Bundle。
IEnumerator DownloadManifestFile(string fullBundlePath) { WWW ManifestBundleFromWWW = new WWW(fullBundlePath); yield return ManifestBundleFromWWW; if (string.IsNullOrEmpty(ManifestBundleFromWWW.error)) { AssetBundle bundle = ManifestBundleFromWWW.assetBundle; AssetBundleManifest[] abms = bundle.LoadAllAssets<AssetBundleManifest>(); if (abms.Length == 1) { string[] allAssetBundleNames = abms[0].GetAllAssetBundles(); Hash128[] allAssetBundleHashes = new Hash128[allAssetBundleNames.Length]; for (int i = 0; i < allAssetBundleNames.Length; i++) allAssetBundleHashes[i] = abms[0].GetAssetBundleHash(allAssetBundleNames[i]); } bundle.Unload(false); } else Debug.Log(ManifestBundleFromWWW.error); yield return null; }
根据以上我们得到的AssetBundle的Name和Hash值,再加上前边服务器的地址,我们便可以得到每一个Bundle的地址以及每一个Bundle的Hash值,通过WWW.LoadFromCacheOrDownload(url,hash)便可动态加载所有的Bundle,只有Bundle发生变化时才会从指定地址重新下载。
在加载AssetBundle时,根据AssetBundle的名字进行加载。
string detailBundlePath = "(BundleAddress)/(BundleName)";//BundleName为上边的allAssetBundleNames[N] WWW www = new WWW(detailBundlePath);//WWW.LoadFromCacheOrDownload(detailBundlePath, hash);//这一行可以通过Hash值来判断是否需要下载。 yield return allAssetBundleFromWWW[bundleIndex]; AssetBundle bundle = www.assetBundle; GameObject[] allObjs = bundle.LoadAllAssets<GameObject>();//可以根据不同的类型加载不同的AssetBundle。
值得注意的是,在WebGL中,测试版本是5.6.2f,使用WWW.LoadFromCacheOrDownload()方法进行下载时,会出现浏览器占用大量内存的情况,暂时还没有找到合适的解决方法,只能通过new WWW(url)来暂时实现需要的功能。要使用WWW.LoadFromCacheOrDownload()方法在WebGL中还需要深入的研究。
来自:https://blog.csdn.net/beihuanlihe130/article/details/76216072