AssetBundle打包

时间:2024-04-13 21:20:23

AssetBundle技术的概念

  Unity的AssetBundle是一个资源压缩包,包含模型、贴图、预制体、声音甚至整个场景,可以在游戏运行时被加载。
  AssetBundle自身保存着相互的依赖关系,压缩包可以使用LZMALZ4压缩算法,减少包大小,更快的进行网络传输,把一些可以下载的内容放在AssetBundle里面,可以减少安装包的大小。

AssetBundle的本质

  AssetBundle是一个存于硬盘上的文件,压缩包中包含了多个文件,如各种图片、声音等等,方便快速加载,可以在Editor上读取,方便查看,可以通过代码从一个特定的压缩包中加载出来对象,这个对象包含了所有添加到这个压缩包里面的内容,可以通过这个对象加载出来

AssetBundle的作用

  AssetBundle的主要作用为优化安装包的大小,如比较耗费资源的模型、场景、预制体等资源都可以放到AssetBundle包中,在运行时动态下载后加载,安装包就不会那么大。

打包(资源分包)的策略

  生成AssetBundle包是不能将所有的资源都生成到一个包中,因为这样会导致AssetBundle包的体积过大,造成下载 加载过慢 会影响用户体验 ,也不能为每个资源生成一个包,这样会耗费大量的加载时间,也会影响用户体验。

常用的打包分组策略
  1. 安装逻辑实体分组
    一个UI界面或者所有UI界面为一个包
    一个角色或者所有角色为一个包
    所有场景共享的部分为一个包
  2. 按照类型分组
    所有声音资源为一个包
    所有Shader为一个包
    所有模型为一个包
    所有材质为一个包
  3. 按照使用分组
    把在某个时间内使用的所有资源打包成一个包
    按照关卡分 一个关卡需要的所有资源 包含角色 贴图 声音等为一个包
    按照场景分 一个场景需要的资源为一个包

打包注意事项
把经常更新的资源放在一个单独包内 与不经常更新的包分离
把需要同时加载的资源放在一个包内
可以把其他包共享的资源放在一个单独的包中
把一些需要同时加载的小资源打包成一个包

  Unity中AssetBundle的打包和分包策略主要针对资源的整理和分组,以方便管理,又能有效优化资源的加载和内存使用。

资源管理的途径

  1. 打包资源的预处理:为了减少AssetBundle的大小和数量,可以先对资源进行预处理,如压缩纹理、优化模型、剪辑音频等
  2. 资源的分组打包
  3. 公共资源的处理
  4. 加载依赖的管理
  5. 版本管理

热更新的步骤

  1. 总体步骤:
    资源打包(开发者)
    上传服务器(开发者)
    从服务器下载(客户端)
    资源包解包并加载数据到程序中(客户端)

资源打包成AssetBundle:
对场景的资源做一个标记,该标记用于确定哪些资源需要打包,已经打包时的分类
在这里插入图片描述

[MenuItem("AssetBundle/Build")]
public void Build()
{
	BuildPipeline.BuildAssetBundles(Application.dataPath+"/AssetBundles");
}

注意点:

要打包的资源的Asset Label必须全部小写(大写会被自动转换为小写),可以带扩展名、版本名

形如“xxx/yyy”的Asset Label 会转化为xxx文件夹下的yyy资源包

面试场景:如何按照路径去打包资源

答:给每一个资源添加一个路径(Asset Label) + / 资源包的名称

Unity会自动处理依赖关系:
比如一个模型依赖于一个材质,如果模型和材质分属不同AssetBundle,则材质中的贴图文件变化时,只需要更新材质的AssetBundle即可,从而减少资源打包的时间和数量。

Unity能够支持任意一种该引擎能够识别的资源类型的打包:
除了脚本资源,移动平台不支持网络下载脚本并执行,因为可能会存在安全隐患,从而导致游戏上架审核失败。

脚本资源的热更新需要额外处理:方法就是利用C#反射机制绑定UnityAPI,在上层进行调用(此外,你无法调用你通过审核以外的API功能)

Unity支持txt、xml、json格式的文件打包,预制体、模型、音频、贴图等都可以打包,但无法打包脚本。

关于二进制资源的打包:

  • Unity支持二进制资源的打包
    • 扩展名以.bytes结尾。
    • Unity会将其识别为TextAsset类型。
    • 在将二进制文件下载到本地后,程序员按TextAsset类型对其进行解包。
    • 也可以将其他Unity不能识别的格式的资源改名为.bytes进行打包。

手机上需要发布到Application.streamingAssetsPath下,因为只有该目录下的内容会被发布到真机上(首先需要新建一个Assets/Streaming Assets文件夹)

打包场景需要调用BuildPipeline.BuildPlayer();方法

热更新时序图
在这里插入图片描述动态加载的好处:
如果游戏场景资源比较多,按需加载可以降低消耗
比如大地图的MMORPG这样的类型的游戏,更是要降低消耗,按需加载

3、资源包上传到服务器

4、从服务器下载资源到本地
非缓存方式:

string url="file:///"+Application.dataPath+"/AssetBundles/XXX";
WWW www=new WWW(url);
yield return www;

file///:这是表示紧跟其后的路径指向本地文件系统的协议前缀。在file:后面的三斜杠是标准用法,用于表示一个不含主机消息(因为我们处理的事本地文件)的绝对文件路径。

缓存方式:

WWW www=WWW.LoadFromCacheOrDownload(url,version);//这里的版本可以从服务器的version.cfg文件下载。
yield return wwww;
	WWW www;
    public Text text;
    void Start()
    {
        //完善的热更新解决方案需要以下步骤
        //启动程序时,将StreamingAsset中的资源包移动到PersistantDataPath
        //检查服务器上资源有没有发生更新,有的话下载更新
        //简单学习,只要从服务器下载资源并载入数据即可

        StartCoroutine(DownLoadAB());//启动携程
    }

    public IEnumerator DownLoadAB()
    {
        //print("DownLoadAB");
        //yield return null;
        //yield break;//中断协程
       www = new WWW("http://localhost:6688/AssetBundles/my");
        
        yield return www;//等待下载结束

        print("Download complete");

       GameObject cubePrefab= www.assetBundle.LoadAsset<GameObject>("MyCube.prefab");

        Instantiate(cubePrefab);
    }
    private void Update()
    {
        text.text = string.Format("{0}%", www.progress * 100);
    }

总资源加载

一般不能直接在Update中下载资源,而是由主线程显示下载的进度,开启携程下载数据
当不清楚资源的依赖关系时,可以先将其总资源包加载,取得相关的依赖项进行加载

 //下载总资源包
        www = new WWW("http://localhost:6688/AssetBundles/AssetBundles");
        yield return www;
        AssetBundleManifest mainfest = www.assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

        //取得相关的依赖项
        string[] dep = mainfest.GetAllDependencies("我的预制体");
        //将相关的依赖项全部加载
        foreach (string s in dep)
        {
            //print(s);
            www=new WWW("http://localhost:6688/AssetBundles/"+s);
            yield return www;
            www.assetBundle.LoadAllAssets();
        }

注意
1、www的资源是直接加载到内存中的,所以用完就要即时释放

//未用资源的加载
www.assetBundle.Unload(false);

2、www的资源不能缓存,需要我们手动实现数据缓存已经和服务器版本比较功能。

卸载AssetBundle:
Asset加载进来后就可以释放AssetBundle了,调用AssetBundle.Unload(unloadAllLoadedObjects)即可。

  • 传入true:卸载该bundle中所有的Asset
  • 传入false:卸载当前未被使用的所有的Asset

5、解包AssetBundle


AssetBundle的使用

AssetBundle工作流程

主要作用:在游戏运行过程中对资源进行动态的下载和加载。
通过AssetBundle将游戏中所需的各种资源打包压缩并上传到网络服务器上
在运行时游戏可以从服务器上下载该资源,从而实现资源的动态加载。

AssetBundle的工作流程

1、开发过程中,开发者创建AssetBundle文件并上传到服务器上。
  创建AssetBundle:开发者可以在Unity编辑器中通过脚本来创建满足要求的AssetBundle文件夹。

  上传至服务器:开发者创建好AssetBundle文件后,即可通过上传工具(比如FTP等)将其上传至服务器中,从而使游戏通过访问服务器来获取所需的资源。

  游戏运行时,客户端会根据实际需求从服务器上将适当的AssetBundle下载到本地机器,再通过加载模块将其资源加载到游戏当中。

  下载AssetBundle:Unity提供了一套完整的API 供开发者使用,从而完成从服务端下载AssetBundle文件。

   www = new WWW("http://localhost:6688/AssetBundles/my");
   yield return www;//等待下载结束
   GameObject cubePrefab= www.assetBundle.LoadAsset<GameObject>("MyCube.prefab");

  加载AssetBundle中的Asset:AssetBundle文件一旦下载完成,开发者即可通过特定的API来加载其所包含的Assets,包括模型、纹理、动画片段等。

  Unity5对Unity4的AssetBundle系统进一步简化,提供了更简单的UI和更简单的脚本,Unity在Build时会自动处理依赖关系,并生成一个.manifest文件,以及AssetBundle的增量式发布。

AssetBundle在Unity中的使用

  AssetBundle是Unity引擎提供的一种用于存储资源的文件格式,它可以存储任意一种Unity引擎能够识别的资源,例如模型、纹理、音频、动画片段甚至整个场景。

  同时,AssetBundle也可以包含开发者自定义的二进制文件,只需将二进制文件的后缀名改为".bytes",Unity引擎即可将其识别为TextAsset,进而可以被打包到AssetBundle文件中

  用户可以通过AssetBundle的UI和简单的脚本在Unity中创建AssetBundle文件,Unity引擎提供了二中创建AssetBundle的API

BuildPipeline.BuildAssetBundles()
通过该接口,开发者可以将编辑器中指定的Asset打包
BuildPipeline.BuildPlayer()
通过该接口,开发者可以讲场景编译成播放器

AssetBundle的UI

  Unity5提供了一个简单AssetBundle的UI,可以让用户简单快速的将Asset标记到AssetBundle

  在资源的Inspector视图中的下方会出现一个AssetBundle的UI,其中第一个选项表示该资源所标记的AssetBundle名称(即该资源会打包到这个名称的AssetBundle中),第二个参数用于设置AssetBundle Variant,主要应用在不同分辨率资源的使用和动态替换AssetBundle。

  当AssetBundle标记的对象很多时,想要看到某个AssetBundle中的资源时,可以单击AssetBundle的名称选项,在弹出的菜单中选择”Filter Selected Name”项,或者在Project视图中搜索”b:AssetBundle名称”,即可查找该AssetBundle里包含的所有资源

  AssetBundle的标记名称要小写,可以有后缀(如:a.assetbundle/a.unity3d),Script(脚本)不能标记AssetBundle。

BuildPineline.BuildAssetBundles

public static AssetBundleMainfest BuildAssetBundles(string outputPath ,BuildAssetBundleOPtions assetBundleOptions=BuildAssetBundleOptions.None ,BuildTarget targetPlatform=BuildTarget.WebPlayer)

如果要将多个资源一起打包,只要将它们的AssetBundle名称设置成一样就可以了

AssetBundle的增量式打包仅重新打包发生变化的AssetBundle,当Asset文件发生变化或者TypeTree发生变化时才会重新打包。

BuildPileline.BuildPlayer()

BuildPlaye()

public static string BuildPlayer(string[] levels,string locationPathName , BuildTarget target ,BuildOptions options)

levels :包括在build里的场景,如果空,当前打开的场景将被编译。路径是相对项目文件夹(Assets/MyLevels/MyScene.unity)
locationPathName:将被编译应用程序的路径,必须包括所有必要的文件扩展名
target:用于指定要编译的BuildTarget
options:额外的编译选项,多个选项可以组合在一起,例如是否运行那种播放器

[MenuItem("Build/BuildWebplayer")]
static function MyBuild()
{
	var levels: String[]=["Asset/Scene1.unity","Asset/Scene2.unity"];
	BuildPipeline.BuildPlayer(levels,"WebPlayerBuild" , BuildTarget.WebPlayer,BuildOptions.None);
}

BuildAssetBundleOption选项
在创建AssetBundle文件的时候,Unity提供了若干个创建选项,每个选项的作用
None:
构建AssetBundle没有任何特殊的选项。

DisableWriteTypeTree:
在AssetBundle中不包含类型信息。但需要注意的事,如果将AssetBundle发布到Web平台上,则不能使用该选项

DeterministicAssetBundle
使每个Object具有唯一不变的hash ID ,可用于赠量式发布AssetBundle。

UncompressedAssetBundle
不进行数据压缩。如果使用该选项,因为没有压缩/解压缩的过程,AssetBundle的发布和加载会更快,但是AssetBundle也会更大,导致下载速度变慢

ForceRebuildAssetBundle
强制重新Build所有的AssetBundle

IngoreTypeTreeChanges
忽略TypeTree的变化,不能与DisableTypeTree同时使用。

AppendHashToAssetBundleName
附加Hash到AssetBundle名称中。

BuildTarget选项
目标的构建平台

  AssetBundle在不同平台之间是不完全兼容的,在多个独立平台构建的AssetBundle可以再这些平台上加载,但并不能在IOS和Android上加载,这需要单独指定他们的BuildTarget。此外,Android和IOS之间也不能相互兼容。

Unity处理Asset之间的依赖关系

Unity会自动处理Asset之间的依赖关系,并把这种依赖关系Build到AssetBundle之中,不再需要通过PopAssetDependencies()/PushAssetDenpencies()来处理依赖关系。

Unity提供了Manifest文件向用户展示这些依赖关系,在处理Assets的依赖关系时不再需要重新打包整个依赖链

1、Cube>Material>Texture
2、Cube.unity3d>material.unity3d
3、更新Material的Texture
4、只需重新打包,material.unity3d即可
在Editor模式下,Unity为每个AssetBundle都会生成一个Manifest文件,在Manifest文件中包含:
1、CRC
2、所包含的Assets
3、所依赖的AssetBundles
4、Hash
5、ClassTypes

AssetBundle Manifest提供了以下访问接口:
GetAllAssetBundles()
获得所有的AssetBundle的Manifest。

GetAllAssetBundlesWithVariant()
获取所有Variant的AssetBundles的Manifest

GetDependencies(string)
获取给定AssetBundle所依赖的AssetBundles。

GetAssetBundleHash(string)
获取给定AssetBundle的Hash。

GetDirectDependencies(string)
获取给定AssetBundle直接依赖的AssetBundles。

WWW wwwManifest = new WWW(manifestPath);
yield return wwwManifest;
AssetBundle manifestBundle = wwwManifest.assetBundle;
AssetBundleManifest manifest = (AssetBundleManifest)manifestBundle.LoadAsset("AssetBundleManifest");
manifestBundle.Unload(false);
string[] allAssetBundles = manifest.GetAllAssetBundles();
//assetBundleName为assetbundle名称.
string[] depedentAssetBundles =   manifest.GetAllDependencies(assetBundleName);

在对资源打包后,在输出的路径文件下会有一个总的manifest文件,文件名与所在的文件夹名称相同,然后每一个大包的资源分别会有一个自己的manifest文件。

Name:表示AssetBundle的名称
Dependencies:表示该AssetBundle所依赖的AssetBundle,如果内容为空,则说明该AssetBundle没有依赖的AssetBundle

如何下载AssetBundle

Unity引擎提供了两种方式来从服务器上动态下载AssetBundle文件
1、非缓存机制
通过创建一个WWW实例来对AssetBundle文件进行下载。下载后的AssetBundle文件将不会进如Unity引擎特定的缓存区

IEnumerator Start()
{
	//开始从指定的URL下载
	WWW www=new WWW(url);
	yield return www;
}

2、缓存机制
  通过WWW.LoadfromCacheorDownload接口来下载AssetBundle文件。下载后的AssetBundle文件将自动被存放在Unity引擎特定的缓存区,该方法是Unity推荐的AssetBundle文件下载方式。

  在下载AssetBundle文件时,该接口会先根据版本号在本地缓存区中查找该文件,看其之前是否被下载过。

  如果下载AssetBundle文件时,该接口会先根据版本号在本地缓存区中查找该文件,看其之前是否被下载过。如果下载过,则直接从缓存区将其读入进来;

  如果没有,则从服务器下进行下载。这中做法的好处是,可以节省AssetBundle文件的下载时间,从而提高游戏资源的载入速度
需要注意的是:
Unity提供的缺省缓存大小事根据发布平台的不同而不同的。
目前,对于发布到Web Player上的网页游戏,缓存缺省大小为50M
对于发布到PC上的客户端游戏和发布到IOS/Android上的移动游戏,缓存缺省大小为4G
开发商可以通过购买有Unity提供的Caching license来增大网页平台上的缓存大小,该授权可以极大地提供网页游戏的运行流畅度。

IEnumerator Start()
{
	//开始从指定的URL下载
	WWW www=WWW.LoadFromCacheOrDownload(url,5);
	//等待下载完成
	yield return www;
	
}

AssetBundle的加载与卸载
如果加载AssetBundle
当AssetBundle文件从服务器下载到本地之后,需要将其加载到内存中并创建AssetBundle文件内存对象。

Unity提供了四种方式来加载AssetBundle文件:

1、WWW.asssetbundle属性
可以通WWW.asssetbundle属性来创建一个AssetBundle文件的内存对象。

IEnumerator Start()
{
	WWW www=WWW.LoadFromCacheOrDownload(url,5);
	yield return www;
	if(www.error!=null)
	{
		Debug.Log(www.error);
		return;
	}
	AssetBundle myLoadedAssetBundle=www.assetBundle;
}

2、AssetBundle.CreateFormFile()
完整定义

public static AssetBundle CreateFromFile(string path)

  通过该接口可以从磁盘文件创建一个AssetBundle文件的内存对象。需要注意的是,该方法仅支持非压缩格式的AssetBundle,即在创建AssetBundle时必须使用UncompressedAssetBundle选项。

3、AssetBundle.CreateFromMemory()

public static AssetBundleCreateRequest CreateFromMemory(byte[] binary)

通过该接口可以创建一个异步AssetBundle内存区域。
比如当用户对AssetBundle进行加密时,可以先调用解密算法返回解密后的数据流,然后再通过AssetBundle.CreateFromMemory从数据流创建AssetBundle对象。

IEnumerator Start()
{
	//开始下载AssetBundle
	var www=WWW.LoadFromCacheOrDownload(url ,5);
  //等待下载完成
  yield return www;
  //从bytes数组中创建AssetBundle
  AssetBundleCreateRequest assetBundleCreateRequest=AssetBundle.CreateFromMemory(www.bytes);
  yield return assetBundleCreateRequest;
  AssetBundle assetBundle=assetBundleCreateRequest.assetBundle;
}

4、AssetBundle.CreateFromMemoryImmediate

public static AssetBundle CreateFromMemoryImmediate(byte[] binary)

通过该接口可以同步创建一个AssetBundle内存区域

IEnumerator Start()
{
	   WWW www = new WWW("http://myserver/myBundle.unity3d");
       yield return www;
       AssetBundle assetBundle = AssetBundle.CreateFromMemoryImmediate(www.bytes);
}

  需要注意的是:如果AssetBundle之间存在依赖关系,要先加载总的manifest文件,通过manifest文件加载对应的依赖文件,然后再加载要加载的AssetBundle。

public class LoadAssets:MonoBehavior
{
		//总的manifest文件名称
		public string manifestName="AssetBundles";
		//要加载的AssetBundle名称
		public string assetBundleName="test";

 		IEnumerator Start()
 		{
 			//assetbundle所在的路径
 			string assetBundlePath="file://"+Application.dataPath+"/AssetBundles";
 			 //manifest文件所在路径
 			 string manifestPath=AssetBundlePath+manifestName;
 			 //首先加载manifest文件
 			 WWW wwwManifest=WWW.LoadFromCacheOrDownload(manifestPath,0);
 			 yield return wwwManifest;
 			 if(wwwManifest.error==null)
 			 {
 			 		AssetBundle manifestBundle=wwwManifest.assetBundle;
 			 		AssetBundleManifest manifest=(AssetBundleManifest)manifestBundle.LoadAsset("AsssetBundleManifest");
 			 		manifestBundle.Unload(false);
					
					//获取依赖文件列表
					string[] depedentAssetBundles=manifest.GetAllDependenies(assetBundleName);
					AssetBundle[] abs=new AssetBundle[depedentAssetBundles.Length];
					for(int i=0;i<depedentAssetBundles.Length;i++)
					{
						//加载所有的依赖文件
						WWW www=WWW.LoadFromCacheOrDownload(assetBundlePath+depedentAssetBundles[i],0);
						yield return www;
						abs[i]=www.assetBundle;
					}
					//加载需要的文件
					WWW www2=WWW.LoadFromCacheOrDownload(assetBundlePath+assetBundleName,0);
					yield return www2;
					AssetBundle assetBundle=www2.assetBundle;

 			 }
 			 else
 			 {
 			 			Debug.Log(wwwManifest.error);
 			 }
 		}
}

如何从AssetBundle中加载Assets
当AssetBundle文件加载完成后,就可以将所包含的Assets加载到内存中,Unity提供了六种加载API进行开发

AssetBundle.LoadAsset()
该接口可以通过名字来将AssetBundle文件中包含的对应Asset名称同步加载到内存中,也可以通过参数来指定加载Asset的类型
AssetBundle.LoadAllAsync()
该接口的作用与AssetBundle.LoadAsset相同,不同的是该接口是对Asset进行异步加载,即加载时主线程可以继续执行
AssetBundle.LoadAllAssets()
该接口用来一次性同步加载AssetBundle文件中的所有Assets,同AssetBundle.LoadAsset一样,可以通过指定加载Asset的类型来选择性地加载Assets。
AssetBundle.LoadAllAseetAsync()
该接口用来一次性异步加载AssetBundle文件中的所有Assets
AssetBundle.LoadAllAssetWithSubAssets()
该接口可以通过名字同步加载AssetBundle文件中的Assets的子Assets,同AssetBundle.LoadAsset一样,可以通过指定加载Asset的类型来选择性地加载Assets。

在Unity5后,不再支持直接Load组件类型,先试用Load游戏对象然后查找组件对象

IEnumerator Start()
{
	WWW www=WWW.LoadFromCacheOrDownload(url,1);
	yield return www;
	//取得AssetBundle
	AssetBundle bundle=www.assetBundle;
	//异步加载对象
	AssetBundleRequest request=bundle.LoadAssetAsync("myObject",typeof(GameObject));
	//等待异步完成
	yield return request;
	//获得加载对象的引用
	GameObject obj=request.asset as GameObject;
	//从内存中卸载AssetBundle
	bundle.Unload(false);//将没有使用的资源卸载
}

如何从场景AssetBundle中加载Assets

Application.LoadLevel
该接口可以通过名字或者索引载入AssetBundle文件中包含的对应场景。当加载新场景中,所有之前加载的GameObject都会被销毁
Application.LoadLevelAsync
该接口的作用与Application.LoadLevel相同,不同的是该接口是对场景进行异步加载,即加载时主线程可以继续执行
Application.LoadLevelAdditive
不同于Application.LoadLevel的是,它并不销毁之前加载的GameObject。
Application.LoadLevelAdditiveAsync
该接口的作用与Application.LoadLevelAdditive相同,不同的是该接口是对场景进行异步加载,即加载时主线程可以继续执行。
Application.LoadLevelAsync接口异步加载场景
public class LoadScenes:MonoBehaviour{
	//场景文件名字
	public string sceneAssetBundle;
	//场景名称
	public string sceneName;
	IEnumerator Start()
	{
		//场景AssetBundle路径
		string path="file://"+Application.dataPath+"/AssetBundles/"+sceneAssetBundle;
		WWW www=WWW.LoadFromCacheOrDownload(path,0);
		yield return www;
		if(www.error==null)
		{
			AssetBundle ab=www.assetBundle;
			AsyncOperation async=Application.LoadLevelAsync(sceneName);
			yield return async;
		}
		else
		{
			Debug.Log(www.error);
		}
	}
}

AssetBundle Variant的使用

AssetBundle Variant通过AssetBundle用来实现Virtual Asset,和不同分辨资源的使用,最终达到在运行时动态替换AssetBundle。
AssetBundle名称相同但不同AssetBundle Variant的AssetBundle之间将有共同的内部id,所以它们之间可以任意切换。
用户可以通过AssetBundle的UI来设置
AssetImporter.assetBundleVariant:

AssetImporter assetImporter=new AssetImporter();
assetImporter.assetBundleVariant="hd";

AssetBundleBuild.assetBundleVariant:

AssetBundleBuild assetBundleBuild =new AssetBundleBuild();
assetBundleBuild.assetBundleVariant="sd";

AssetBundle Variant会用于AssetBundle的后缀名中

AssetImporter.assetBundleName="myassets";
assetBundleBuild.assetBundleVariant="hd";
最终AssetBundle name为"myassets.hd"

AssetBundle的内存管理
内存管理是游戏制作中非常重要的一步。
在这里插入图片描述

下载和加载AssetBundle时对内存的影响
1、AssetBundle文件的下载和加载
  在下载时可通过WWW或WWW.LoadfromCacheOrDownload方法从服务端或本地缓存区获得AssetBundle文件,并通过WWW.assetbundle属性加载AssetBundle对象。

Unity引擎在使用WWW方法时会分配一系列的内存空间来存放WWW实例以及Web stream数据。
  该数据包括原始的AssetBundle数据、解压后的AssetBundle数据以及一个用于解压的Decompression Buffer。
一般情况下,Decompression Buffer会在原始的AssetBundle完成解压后自动销毁。但需要主要的是,Unity内部会自动保留一个Decompression Buffer,使其不被系统回收。

例如当同时加载3个AssetBundle时,那么系统会生成3个Decompression Buffer并同时对每个AssetBundle进行解压,当解压完成后,系统会自动销毁其中的2个Decompression Buffer,而留下一个Decompression Buffer,以备下次解压缩AssetBundle时复用。这样的做的好处是,不用过于频繁地开辟和销毁解压Buffer,从而可以在一定程序上降低CPU的小孩

2、资源转换和实例化
  当把AssetBundle解压并加载到内存后,开发者可以通过从WWW.assetbundle属性所获得的AssetBundle对象来得到各种Asset,并对这些Assets进行加载或实例化操作。
  加载过程中,Unity会将AssetBundle中的数据流转变成引擎可识别的信息类型(纹理、材质、对象等)。加载完成后,开发者即可对其进一步的操作,比如对象的实例化、纹理和材质的复制、替换等。

AssetBundle以及Asset的卸载
无论是在下载和加载过程中,还是在Asset加载和实例化过程中,AssetBundle以及由其加载的Assets均会占用内存。

1、AssetBundle的卸载
通过AssetBundle.Unload接口卸载AssetBundle自身
2、从AssetBundle加载的Assets的卸载
对于从AssetBundle加载的Asset,比如纹理、材质、音频片段和动画片段等,有两种方式进行卸载

Assetbundle.Unload(