unity assetbundlee.createfromfile比www快吗

这几天一直在研究热更新方案
主要思路是:
1.先将代码打包成dll,然后用unity 打包成assetsbundle,
2.WWW加载进入主程序,
3使用System.Reflection.Assembly来创建程序集,
4.然后通过GetType(className),来获取这个类
5.AddComponent进入主程序,加载的dll就执行起来了。
ExportAssetBundles.cs
//打包工具,该工具是网上找来都。谢谢作者!
public class ExportAssetBundles : MonoBehaviour {
//在Unity编辑器中添加菜单
[MenuItem("Custom Editor/Create AssetBunldes ALL")]
static void ExportResource()
// 打开保存面板,获得用户选择的路径
string path = EditorUtility.SaveFilePanel("Save Resource", "", "New Resource", "assetbundle");
if (path.Length != 0)
// 选择的要保存的对象
Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
BuildPipeline.BuildAssetBundle(Selection.activeObject, selection, path, BuildAssetBundleOptions.CollectDependencies | pleteAssets, BuildTarget.StandaloneWindows);
1234567891011121314151617181920
//打包工具,该工具是网上找来都。谢谢作者!public class ExportAssetBundles : MonoBehaviour {&&&&&//在Unity编辑器中添加菜单&&&&&&[MenuItem("Custom Editor/Create AssetBunldes ALL")]&&&&static void ExportResource()&&&&{&&&&&&&&// 打开保存面板,获得用户选择的路径&&&&&&&&&&string path = EditorUtility.SaveFilePanel("Save Resource", "", "New Resource", "assetbundle");&&&&&&&&&if (path.Length != 0)&&&&&&&&{&&&&&&&&&&&&// 选择的要保存的对象&&&&&&&&&&&&&&Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);&&&&&&&&&&&&//打包&&&&&&&&&&&&&&BuildPipeline.BuildAssetBundle(Selection.activeObject, selection, path, BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets, BuildTarget.StandaloneWindows);&&&&&&&&&&&&&&}&&&&}&&}
using UnityE
using System.C
using System.R
//代码加载器
public class Index : MonoBehaviour
private WWW
public static WWW uiWWW;
private System.Reflection.A
// Use this for initialization
void Start ()
StartCoroutine(loadScript());
private IEnumerator loadScript()
//加载我的代码资源
www = new WWW("http://localhost/Main.assetbundle");
AssetBundle bundle = www.assetB
TextAsset asset = bundle.Load("Main", typeof(TextAsset)) as TextA
assembly = System.Reflection.Assembly.Load(asset.bytes);
Assembly[] assLis = System.AppDomain.CurrentDomain.GetAssemblies();
System.Type script = assembly.GetType("Main");
gameObject.AddComponent(script);
12345678910111213141516171819202122232425262728293031323334353637
using UnityEngine;using System.Collections;using System.Reflection;&//代码加载器public class Index : MonoBehaviour{&&&&&private WWW www;&&&&&public static WWW uiWWW;&&&&&private System.Reflection.Assembly assembly;& // Use this for initialization void Start () &&&&{&&&&&&&&StartCoroutine(loadScript()); }&&&&&private IEnumerator loadScript()&&&&{&&&&&&&&//加载我的代码资源&&&&&&&&www = new WWW("http://localhost/Main.assetbundle");&&&&&&&&yield return www;&&&&&&&&&AssetBundle bundle = www.assetBundle;&&&&&&&&TextAsset asset = bundle.Load("Main", typeof(TextAsset)) as TextAsset;&&&&&&&&assembly = System.Reflection.Assembly.Load(asset.bytes);&&&&&&&&&Assembly[] assLis = System.AppDomain.CurrentDomain.GetAssemblies();&&&&&&&&&System.Type script = assembly.GetType("Main");&&&&&&&&&gameObject.AddComponent(script);&&&&}}
因为在加载的时候遇见安全沙箱问题,所以我将这个策略文件记录下来,方便下次复制粘贴
crossdomain.xml
&?xml version="1.0"?&
&cross-domain-policy&
&site-control permitted-cross-domain-policies=”master-only” /&
&allow-access-from domain="" /&
&allow-access-from domain="*"/&
&/cross-domain-policy&
&?xml version="1.0"?&&cross-domain-policy&&site-control permitted-cross-domain-policies=”master-only” /&&allow-access-from domain="" /&&allow-access-from domain="*"/&&/cross-domain-policy&
本地调试程序时解决跨域问题的方法:
Edit-&Project Settings-&Eidtor
刚开始的时候想使用序列化来存储一些数据,但是后来却连一个很简单的类序列化dll里面都没法获得
官方对象序列号
[MenuItem("Custom Editor/WriteSpriteData")]
static void FileWriteSpriteData()
TextAsset textasset = AssetDatabase.LoadAssetAtPath("Assets/Resources/Packer/Packer.txt", typeof(TextAsset)) as TextA
Atlas atlas = ScriptableObject.CreateInstance&Atlas&();
//Json其实是NGUIJson这个类,我只是把他提出来。改了个名字
atlas.mList = Json.LoadSpriteData(textasset as TextAsset);
if (atlas.mList == null)
string path = "Assets/Resources/Packer/Packer.asset";
AssetDatabase.CreateAsset(atlas, path);
//Atlas是一个只有一个mList属性都类 mList = new List&UISpriteData&();
Object o = AssetDatabase.LoadAssetAtPath(path, typeof(Atlas));
Object texture = AssetDatabase.LoadAssetAtPath("Assets/Resources/Packer/Packer.mat", typeof(Material));
Object[] t = {texture};
BuildPipeline.BuildAssetBundle(o, t, "Assets/Resources/Packer/Packer.assetbundle");
//AssetDatabase.DeleteAsset(path);
12345678910111213141516171819202122232425
[MenuItem("Custom Editor/WriteSpriteData")]&&&&static void FileWriteSpriteData()&&&&{&&&&&&&&TextAsset textasset = AssetDatabase.LoadAssetAtPath("Assets/Resources/Packer/Packer.txt", typeof(TextAsset)) as TextAsset;&&&&&&&&&Atlas atlas = ScriptableObject.CreateInstance&Atlas&();//Json其实是NGUIJson这个类,我只是把他提出来。改了个名字&&&&&&&&atlas.mList = Json.LoadSpriteData(textasset as TextAsset);&&&&&&&&&if (atlas.mList == null)&&&&&&&&&&&&return;&&&&&&&&&string path = "Assets/Resources/Packer/Packer.asset";&&&&&&&&&AssetDatabase.CreateAsset(atlas, path);//Atlas是一个只有一个mList属性都类 mList = new List&UISpriteData&();&&&&&&&&Object o = AssetDatabase.LoadAssetAtPath(path, typeof(Atlas));&&&&&&&&Object texture = AssetDatabase.LoadAssetAtPath("Assets/Resources/Packer/Packer.mat", typeof(Material));&&&&&&&&&Object[] t = {texture};&&&&&&&&&BuildPipeline.BuildAssetBundle(o, t, "Assets/Resources/Packer/Packer.assetbundle");&&&&&&&&&&&&&&&&//AssetDatabase.DeleteAsset(path);&&&&}
这是使用序列化数据的加载方式,在不用反射的情况下,下面代码加载能够成功,但是使用了反射,下面的代码就加载不成功了。这个问题我也很费解,暂时我没办法解决
读取序列化对象
IEnumerator LoadAtlas()
www = new WWW("http://localhost/Packer.assetbundle");
//WoodenAtlas.assetbundle
//Packer.assetbundle
//用来断点都时候看看里面所包含都数据
Object[] os = www.assetBundle.LoadAll();
Material mete = www.assetBundle.Load("Packer", typeof(Material)) as M
Atlas atlas = www.assetBundle.mainAsset as A
GameObject go = new GameObject("UIAtlas");
UIAtlas uiatlas = go.AddComponent&UIAtlas&();
uiatlas.spriteMaterial =
uiatlas.spriteList = atlas.mL
GameObject sprite = new GameObject("Sprite");
UISprite ui = NGUITools.AddChild&UISprite&(sprite);
ui.atlas =
ui.spriteName = "dynamite";
Debug.Log("Load");
www.assetBundle.Unload(false);
www.Dispose();
1234567891011121314151617181920212223242526
IEnumerator LoadAtlas()&&&&{&&&&&&&&www = new WWW("http://localhost/Packer.assetbundle");&&&&&&&&//WoodenAtlas.assetbundle&&&&&&&&//Packer.assetbundle&&&&&&&&yield return www;//用来断点都时候看看里面所包含都数据&&&&&&&&Object[] os = www.assetBundle.LoadAll();&&&&&&&&&Material mete = www.assetBundle.Load("Packer", typeof(Material)) as Material;&&&&&&&&Atlas atlas = www.assetBundle.mainAsset as Atlas;&&&&&&&&GameObject go = new GameObject("UIAtlas");&&&&&&&&UIAtlas uiatlas = go.AddComponent&UIAtlas&();&&&&&&&&uiatlas.spriteMaterial = mete;&&&&&&&&uiatlas.spriteList = atlas.mList;&&&&&&&&&GameObject sprite = new GameObject("Sprite");&&&&&&&&UISprite ui = NGUITools.AddChild&UISprite&(sprite);&&&&&&&&ui.atlas = uiatlas;&&&&&&&&ui.spriteName = "dynamite";&&&&&&&&Debug.Log("Load");&&&&&&&&&www.assetBundle.Unload(false);&&&&&&&&www.Dispose();&&&&&&&&&&&&}
因为要看一下代码的执行效率,所以我寻找到了这个类。感觉还可以。使用josn数据,mat文件创建一个UIAtlas的时间大概是30毫秒左右。
System.Diagnostics.S
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Thread.Sleep(10000);
stopWatch.Stop();
System.Diagnostics.Stopwatch;Stopwatch stopWatch = new Stopwatch();stopWatch.Start();Thread.Sleep(10000);stopWatch.Stop();
我使用没有任何Unity环境以外代码来实现壳的制作(我们暂且将其称为Index,其实他就是上面的Index类,代码少得可怜。)
然后主程序是在另一个Unity项目中(这个项目在发布的时候打包成Main.dll)
Main.dll项目通过上面的Index来加载,然后添加到一个GameObject上,主程序的Awake()方法就会执行(Awake是整个程序的主入口)
这个时候所有的资源加载都会在Main.dll里面完成。
在这个过程中,遇到了一个比较麻烦的问题就是,我打包的一些UIAtlas.prefab文件上的UIAtlas这个类,无法找到。
这让我有一些无法理解,因为NGUI的代码已经打包进入了Main.dll,那么为什么我加载prefab的时候,却找不到UIAtlas这个类呢?
最后我只能动态的制作UIAtlas对象来完成这样工作。
那么这样的话,以后做界面,做任何prefab都不能绑定脚本了。都只能加载到内存中动态AddComponent了。这样界面也得用配置文件了。
不过对于我这种从页游转过来的程序,这到不是问题,我有现成的界面编辑器(我博客里有),直接生成XML在游戏中进行组装了。对于能够热更新来说,这点麻烦,其实应该不算麻烦了。
动态生成UIAtlas后,创建了几个Sprite、Button,基本的功能都已经实现,说明这个解决方案是可行的。接下来我将把这个方案运用到我的项目中,更加全面的去实验一下。
这样设计的优点:
1、对IOS的打包也是比较方便。打包IOS 直接拿Main项目打包就可以了。因为不需要热更新了。把代码打包在本地就行了。
2、打包Android项目的时候发布apk只需要发布Index,项目发布版本和没写代码一样大,想到这里我想吐槽一下,Unity就算不写任何代码,发布一个apk也得有7M左右。这也太大了点吧。我可啥都没做啊。
1、哪位大神能给我说说上面我遇到的那个问题,为什么找不到绑定在prefab上的类呢?这是程序集的问题么?哎,刚转C#的人伤不起。
[…] 3、这也是最主要的,如果你看过我上一篇文章《Unity代码热更新解决方案测试结果总结》你就会知道我为什么要这么做了,都是泪啊。。 […]厚积薄发| Unity优化(19)
原文链接:
接上期的讲解,我们今天为大家继续探秘AssetBundle,从管理机制的角度出发,谈谈其资源加载和卸载的原理。
AssetBundle加载基础
通过AssetBundle加载资源,分为两步,第一步是获取AssetBundle对象,第二步是通过该对象加载需要的资源。而第一步又分为两种方式,下文中将结合常用的API进行详细地描述。
一、获取AssetBundle对象的常用API
(1)先获取WWW对象,再通过WWW.assetBundle获取AssetBundle对象:
public WWW(string url);
加载Bundle文件并获取WWW对象,完成后会在内存中创建较大的WebStream(解压后的内容,通常为原Bundle文件的4~5倍大小,纹理资源比例可能更大),因此后续的AssetBundle.Load可以直接在内存中进行。
public static WWW LoadFromCacheOrDownload(string url, int version, uint crc = 0);
加载Bundle文件并获取WWW对象,同时将解压形式的Bundle内容存入磁盘中作为缓存(如果该Bundle已在缓存中,则省去这一步),完成后只会在内存中创建较小的SerializedFile,而后续的AssetBundle.Load需要通过IO从磁盘中的缓存获取。
public AssetBundle assetB
通过之前两个接口获取WWW对象后,即可通过WWW.assetBundle获取AssetBundle对象。
(2) 直接获取AssetBundle:
public static AssetBundle CreateFromFile(string path);
通过未压缩的Bundle文件,同步创建AssetBundle对象,这是最快的创建方式。创建完成后只会在内存中创建较小的SerializedFile,而后续的AssetBundle.Load需要通过IO从磁盘中获取。
public static AssetBundleCreateRequest CreateFromMemory(byte[] binary);
通过Bundle的二进制数据,异步创建AssetBundle对象。完成后会在内存中创建较大的WebStream。调用时,Bundle的解压是异步进行的,因此对于未压缩的Bundle文件,该接口与CreateFromMemoryImmediate等价。
public static AssetBundle CreateFromMemoryImmediate(byte[] binary);
该接口是CreateFromMemory的同步版本。
注:5.3下分别改名为LoadFromFile,LoadFromMemory,LoadFromMemoryAsync并增加了LoadFromFileAsync,且机制也有一定的变化,可详见Unity官方文档。
二、从AssetBundle加载资源的常用API
public Object Load(string name, Type type);
通过给定的名字和资源类型,加载资源。加载时会自动加载其依赖的资源,即Load一个Prefab时,会自动Load其引用的Texture资源。
public Object[] LoadAll(Type type);
一次性加载Bundle中给定资源类型的所有资源。
public AssetBundleRequest LoadAsync(string name, Type type);
该接口是Load的异步版本。
注:5.x下分别改名为LoadAsset,LoadAllAssets,LoadAssetAsync,并增加了LoadAllAssetsAsync。
AssetBundle加载进阶
一、接口对比:new WWW与WWW.LoadFromCacheOrDownload
(1)前者的优势
后续的Load操作在内存中进行,相比后者的IO操作开销更小;
不形成缓存文件,而后者则需要额外的磁盘空间存放缓存;
能通过WWW.texture,WWW.bytes,WWW.audioClip等接口直接加载外部资源,而后者只能用于加载AssetBundle
(2)前者的劣势
每次加载都涉及到解压操作,而后者在第二次加载时就省去了解压的开销;
在内存中会有较大的WebStream,而后者在内存中只有通常较小的SerializedFile。(此项为一般情况,但并不绝对,对于序列化信息较多的Prefab,很可能出现SerializedFile比WebStream更大的情况)
二、内存分析
在管理AssetBundle时,了解其加载过程中对内存的影响意义重大。在上图中,我们在中间列出了AssetBundle加载资源后,内存中各类物件的分布图,在左侧则列出了每一类内存的产生所涉及到的加载API:
WWW对象:在第一步的方式1中产生,内存开销小;
WebStream:在使用new WWW或CreateFromMemory时产生,内存开销通常较大;
SerializedFile:在第一步中两种方式都会产生,内存开销通常较小;
AssetBundle对象:在第一步中两种方式都会产生,内存开销小;
资源(包括Prefab):在第二步中通过Load产生,根据资源类型,内存开销各有大小;
场景物件(GameObject):在第二步中通过Instantiate产生,内存开销通常较小。
在后续的章节中,我们还将针对该图中各类内存物件分析其卸载的方式,从而避免内存残留甚至泄露。
三、注意点
CreateFromFile只能适用于未压缩的AssetBundle,而Android系统下StreamingAssets是在压缩目录(.jar)中,因此需要先将未压缩的AssetBundle放到SD卡中才能对其使用CreateFromFile。
Application.streamingAsstsPath = &jar:file://& + Application.dataPath+&!/assets/&;
iOS系统有256个开启文件的上限,因此,内存中通过CreateFromFile或WWW.LoadFromCacheOrDownload加载的AssetBundle对象也会低于该值,在较新的版本中,如果LoadFromCacheOrDownload超过上限,则会自动改为new WWW的形式加载,而较早的版本中则会加载失败。
CreateFromFile和WWW.LoadFromCacheOrDownload的调用会增加RersistentManager.Remapper的大小,而PersistentManager负责维护资源的持久化存储,Remapper保存的是加载到内存的资源HeapID与源数据FileID的映射关系,它是一个Memory Pool,其行为类似Mono堆内存,只增不减,因此需要对这两个接口的使用做合理的规划。
对于存在依赖关系的Bundle包,在加载时主要注意顺序。举例来说,假设CanvasA在BundleA中,所依赖的AtlasB在BundleB中,为了确保资源正确引用,那么最晚创建BundleB的AssetBundle对象的时间点是在实例化CanvasA之前。即,创建BundleA的AssetBundle对象时、Load(“CanvasA”)时,BundleB的AssetBundle对象都可以不在内存中。
根据经验,建议AssetBundle文件的大小不超过1MB,因为在普遍情况下Bundle的加载时间与其大小并非呈线性关系,过大的Bundle可能引起较大的加载开销。
由于WWW对象的加载是异步的,因此逐个加载容易出现下图中CPU空闲的情况(选中帧处Vsync占了大部分),此时建议适当地同时加载多个对象,以增加CPU的使用率,同时加快加载的完成。
AssetBundle卸载
前文提到了通过AssetBundle加载资源时的内存分配情况,下面,我们结合常用的API来介绍如何将已分配的内存进行卸载,最终达到清空所有相关内存的目的。
一、内存分析
在上图中的右侧,我们列出了各种内存物件的卸载方式:
场景物件(GameObject):这类物件可通过Destroy函数进行卸载;
资源(包括Prefab):除了Prefab以外,资源文件可以通过三种方式来卸载:
1) 通过Resources.UnloadAsset卸载指定的资源,CPU开销小;
2)通过Resources.UnloadUnusedAssets一次性卸载所有未被引用的资源,CPU开销大;
3)通过AssetBundle.Unload(true)在卸载AssetBundle对象时,将加载出来的资源一起卸载。
而对于Prefab,目前仅能通过DestroyImmediate来卸载,且卸载后,必须重新加载AssetBundle才能重新加载该Prefab。由于内存开销较小,通常不建议进行针对性地卸载。
WWW对象:调用对象的Dispose函数或将其置为null即可;
WebStream:在卸载WWW对象以及对应的AssetBundle对象后,这部分内存即会被引擎自动卸载;
SerializedFile:卸载AssetBundle后,这部分内存会被引擎自动卸载;
AssetBundle对象:AssetBundle的卸载有两种方式:
1)通过AssetBundle.Unload(false),卸载AssetBundle对象时保留内存中已加载的资源;
2)通过AssetBundle.Unload(true),卸载AssetBundle对象时卸载内存中已加载的资源,由于该方法容易引起资源引用丢失,因此并不建议经常使用;
二、注意点
在通过AssetBundle.Unload(false)卸载AssetBundle对象后,如果重新创建该对象并加载之前加载过的资源到内存时,会出现冗余,即两份相同的资源。
被脚本的静态变量引用的资源,在调用Resources.UnloadUnusedAssets时,并不会被卸载,在Profiler中能够看到其引用情况。
UWA推荐方案
通过以上的讲解,相信您对AssetBundle的加载和卸载已经有了明确的了解。下面,我们将简单地做一下API选择上的推荐:
对于需要常驻内存的Bundle文件来说,优先考虑减小内存占用,因此对于存放非Prefab资源(特别是纹理)的Bundle文件,可以考虑使用WWW.LoadFromCacheOrDownload或AssetBundle.CreateFromFile加载,从而避免WebStream常驻内存;而对于存放较多Prefab资源的Bundle,则考虑使用new WWW加载,因为这类Bundle用WWW.LoadFromCacheOrDownload加载时产生的SerializedFile可能会比new WWW产生的WebStream更大。
对于加载完后即卸载的Bundle文件,则分两种情况:优先考虑速度(加载场景时)和优先考虑流畅度(游戏进行时)。
1)加载场景的情况下,需要注意的是避免WWW对象的逐个加载导致的CPU空闲,可以考虑使用加载速度较快的WWW.LoadFromCacheOrDownload或AssetBundle.CreateFromFile,但需要避免后续大量地进行Load资源的操作,引起IO开销(可以尝试直接LoadAll)。
2) 游戏进行的情况下,则需要避免使用同步操作引起卡顿,因此可以考虑使用new WWW配合AssetBundle.LoadAsync来进行平滑的资源加载,但需要注意的是,对于Shader、较大的Texture等资源,其初始化操作通常很耗时,容易引起卡顿,因此建议将这类资源在加载场景时进行预加载。
只在Bundle需要加密的情况下,考虑使用CreateFromMemory,因为该接口加载速度较慢。
尽量避免在游戏进行中调用Resources.UnloadUnusedAssets(),因为该接口开销较大,容易引起卡顿,可尝试使用Resources.Unload(obj)来逐个进行卸载,以保证游戏的流畅度。
需要说明的是,以上内存管理较适合于Unity 5.3之前的版本。Unity引擎在5.3中对AssetBundle的内存占用进行一定的调整,目前我们也在进一步的学习和研究中。
以上即为我们这次为您带来的AssetBundle管理机制,希望对您的项目研发有所帮助。我们会在后续技术文章通过大量的案例来进一步解释AssetBundle的管理机制,敬请关注。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6507次
排名:千里之外
原创:35篇Unity3D(18)
AssetBundle(1)
在使用AssetBundle.CreateFromFile加载AssetBundle时有两点需要注意:
1:在创建资源包时需要选择不压缩(unity5.x资源打包方式)
AssetBundleManifest amf
= BuildPipeline.BuildAssetBundles(assetPath , abbs ,BuildAssetBundleOptions.UncompressedAssetBundle , bTarget);
2:在读取时需要注意文件路径
如果打的 AssetBundle 包b.unity3d放在工程目录下的asb文件夹下,则此时路径为:Application.dataPath &+ &/ASB/b.unity3d&
AssetBundle asb = AssetBundle.CreateFromFile(Application.dataPath
+ &/ASB/b.unity3d&);
若使用www加载本地AssetBundle则需要在路径前加“file://”即
&file://& + Application.dataPath
+ &/ASB/b.unity3d&
StreamingAssets目录下的资源不同平台的路径:
#if UNITY_EDITOR
#if UNITY_EDITOR_OSX
path = &file://& + Application.streamingAssetsPath+&/ASB_Ios/sound.unity3d&;
path = &file://& + Application.streamingAssetsPath+&/ASB_Android/sound.unity3d&;
#elif UNITY_ANDROID
path = Application.streamingAssetsPath+&/ASB_Android/sound.unity3d&;
#elif UNITY_IOS
path = &file://&+Application.streamingAssetsPath+&/ASB_Ios/sound.unity3d&;
// path = &file://&+Application.dataPath + &/Raw/ASB_Ios/sound.unity3d&;// +
path = Application.streamingAssetsPath+&/ASB_Android/sound.unity3d&;
资源打包:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:20709次
排名:千里之外
原创:31篇
(1)(1)(2)(2)(3)(2)(1)(2)(5)(1)(15)【厚积薄发】你应该知道的AssetBundle管理机制(上)
AssetBundle内存管理机制
接上期AssetBundle打包的讲解,我们今天为大家继续探秘AssetBundle,从管理机制的角度出发,谈谈其资源加载和卸载的原理。
同时如果你恰有相关疑问,欢迎后台留言给UWA,或者加入QQ群()讨论,当然也不要忘记关注UWA哦。
◆◆◆◆
&AssetBundle加载基础
通过AssetBundle加载资源,分为两步,第一步是获取AssetBundle对象,第二步是通过该对象加载需要的资源。而第一步又分为两种方式,下文中将结合常用的API进行详细地描述。
第一步,获取AssetBundle对象的常用API
方式一,先获取WWW对象,再通过WWW.assetBundle获取AssetBundle对象:
●&public
WWW(string url);
加载Bundle文件并获取WWW对象,完成后会在内存中创建较大的WebStream(解压后的内容,通常为原Bundle文件的4~5倍大小,纹理资源比例可能更大),因此后续的AssetBundle.Load可以直接在内存中进行。
&●&public
static WWW LoadFromCacheOrDownload(string url, int version, uint
加载Bundle文件并获取WWW对象,同时将解压形式的Bundle内容存入磁盘中作为缓存(如果该Bundle已在缓存中,则省去这一步),完成后只会在内存中创建较小的SerializedFile,而后续的AssetBundle.Load需要通过IO从磁盘中的缓存获取。
●&public
AssetBundle assetB
通过之前两个接口获取WWW对象后,即可通过WWW.assetBundle获取AssetBundle对象。
方式二,直接获取AssetBundle:
●&public
static AssetBundle CreateFromFile(string path);
通过未压缩的Bundle文件,同步创建AssetBundle对象,这是最快的创建方式。创建完成后只会在内存中创建较小的SerializedFile,而后续的AssetBundle.Load需要通过IO从磁盘中获取。
●&public
static AssetBundleCreateRequest CreateFromMemory(byte[]
通过Bundle的二进制数据,异步创建AssetBundle对象。完成后会在内存中创建较大的WebStream。调用时,Bundle的解压是异步进行的,因此对于未压缩的Bundle文件,该接口与CreateFromMemoryImmediate等价。
●&public
static AssetBundle CreateFromMemoryImmediate(byte[]
该接口是CreateFromMemory的同步版本。
注:5.3下分别改名为LoadFromFile,LoadFromMemory,LoadFromMemoryAsync并增加了LoadFromFileAsync,且机制也有一定的变化,可详见Unity官方文档。
第二步,从AssetBundle加载资源的常用API
●&public
Object Load(string name, Type type);
通过给定的名字和资源类型,加载资源。加载时会自动加载其依赖的资源,即Load一个Prefab时,会自动Load其引用的Texture资源。
●&public
Object[] LoadAll(Type type);
一次性加载Bundle中给定资源类型的所有资源。
●&public
AssetBundleRequest LoadAsync(string name, Type type);
该接口是Load的异步版本。
注:5.x下分别改名为LoadAsset,LoadAllAssets,LoadAssetAsync,并增加了LoadAllAssetsAsync。
◆◆◆◆
AssetBundle加载进阶
接口对比:new WWW与WWW.LoadFromCacheOrDownload
前者的优势
●&&后续的Load操作在内存中进行,相比后者的IO操作开销更小;
●&不形成缓存文件,而后者则需要额外的磁盘空间存放缓存;
●&能通过WWW.texture,WWW.bytes,WWW.audioClip等接口直接加载外部资源,而后者只能用于加载AssetBundle;
前者的劣势
●&每次加载都涉及到解压操作,而后者在第二次加载时就省去了解压的开销;
●&&在内存中会有较大的WebStream,而后者在内存中只有通常较小的SerializedFile。(此项为一般情况,但并不绝对,对于序列化信息较多的Prefab,很可能出现SerializedFile比WebStream更大的情况)
在管理AssetBundle时,了解其加载过程中对内存的影响意义重大。在上图中,我们在中间列出了AssetBundle加载资源后,内存中各类物件的分布图,在左侧则列出了每一类内存的产生所涉及到的加载API:
●&WWW对象:在第一步的方式1中产生,内存开销小;
●&WebStream:在使用new
WWW或CreateFromMemory时产生,内存开销通常较大;
●&SerializedFile:在第一步中两种方式都会产生,内存开销通常较小;
●&AssetBundle对象:在第一步中两种方式都会产生,内存开销小;
●&资源(包括Prefab):在第二步中通过Load产生,根据资源类型,内存开销各有大小;
●&场景物件(GameObject):在第二步中通过Instantiate产生,内存开销通常较小。
在后续的章节中,我们还将针对该图中各类内存物件分析其卸载的方式,从而避免内存残留甚至泄露。
●&CreateFromFile只能适用于未压缩的AssetBundle,而Android系统下StreamingAssets是在压缩目录(.jar)中,因此需要先将未压缩的AssetBundle放到SD卡中才能对其使用CreateFromFile。
Application.streamingAsstsPath = "jar:file://" Application.dataPath
"!/assets/";
●&iOS系统有256个开启文件的上限,因此,内存中通过CreateFromFile或WWW.LoadFromCacheOrDownload加载的AssetBundle对象也会低于该值,在较新的版本中,如果LoadFromCacheOrDownload超过上限,则会自动改为new&WWW的形式加载,而较早的版本中则会加载失败。&
●&CreateFromFile和WWW.LoadFromCacheOrDownload的调用会增加RersistentManager.Remapper的大小,而PersistentManager负责维护资源的持久化存储,Remapper保存的是加载到内存的资源HeapID与源数据FileID的映射关系,它是一个Memory
Pool,其行为类似Mono堆内存,只增不减,因此需要对这两个接口的使用做合理的规划。
●&对于存在依赖关系的Bundle包,在加载时主要注意顺序。举例来说,假设CanvasA在BundleA中,所依赖的AtlasB在BundleB中,为了确保资源正确引用,那么最晚创建BundleB的AssetBundle对象的时间点是在实例化CanvasA之前。即,创建BundleA的AssetBundle对象时、Load(“CanvasA”)时,BundleB的AssetBundle对象都可以不在内存中。
●&根据经验,建议AssetBundle文件的大小不超过1MB,因为在普遍情况下Bundle的加载时间与其大小并非呈线性关系,过大的Bundle可能引起较大的加载开销。
●&由于WWW对象的加载是异步的,因此逐个加载容易出现下图中CPU空闲的情况(选中帧处Vsync占了大部分),此时建议适当地同时加载多个对象,以增加CPU的使用率,同时加快加载的完成。
以上是AssetBundle资源加载部分,有加载自然有卸载,鉴于篇幅,我们将另起一篇,敬请关注!
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。}

我要回帖

更多关于 www.assetbundle 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信