尊重原创,转载请注明出处,谢谢!
http://blog.csdn.net/y1196645376/article/details/52567171
a.BuildPipeline.BuildAssetBundle :打包常规资源生成AssetBundle. |
CompleteAssets : 用于保证资源的完备性,默认开启; CollectDependencies:用于收集资源的依赖项,默认开启; DeterministicAssetBundle:用于为资源维护固定ID,默认开启; ForceRebuildAssetBundle:用于强制重打所有AssetBundle文件,新增; IgnoreTypeTreeChanges:用于判断AssetBundle更新时,是否忽略TypeTree的变化,新增; AppendHashToAssetBundleName:用于将Hash值添加在AssetBundle文件名之后,开启这个选项可以直接通过文件名来判断哪些Bundle的内容进行了更新(4.x下普遍需要通过比较二进制等方法来判断,但在某些情况下即使内容不变重新打包,Bundle的二进制也会变化),新增。 ChunkBasedCompression:用于使用LZ4格式进行压缩,5.3新增。 |
StandaloneWindows: 打包32位windows平台上的包。 StandaloneWindows64: 打包64位windows平台上的包。 iOS: 打包ios平台上的包。 Android : 打包Android平台上的包。 当然远不止支持这几个平台格式,但是其他的平台不是常用就不介绍了。 |
b.BuildStreamedSceneAssetBundle:将场景打包成AsssetBundle包。 |
options : 同上。
www下载好场景AB包之后通过获取成员属性assetBundle就可以吧场景信息读入到内存中了。然后只需要通过Application.LoadLevel(name)就可以加载对应的场景。 |
c.WWW:通过一个路径进行下载(无论是服务器路径还是本地路径下载操作都一样)。 |
Url:下载路径;请注意:如果是本地链接请加上前缀”file://”,如果是http链接请加上前缀”http://”。
www下载后的得到的对象可以通过获取成员属性assetBundle,即可得到下载文件的AB包。不过该方法下载得到的资源统统是放在内存里面的,也就是说每次打开游戏都需要重新下载。 |
d.WWW.LoadFromCacheOrDownload : 通过路径和版本号下载。 |
Version:版本号;请注意这个版本号不需要你自己去维护,每次Unity从服务器下载资源的到本地的时候都会维护这个资源的版本号。当下次调用该API下载该资源会先对比本地版本号和参数版本号是否匹配,如果不匹配就从服务器重新下载,否则就从磁盘缓存文件中读取。
www下载后的得到的对象可以通过获取成员属性assetBundle,即可得到下载文件的AB包。该方法下载的资源是缓存到电脑缓存文件中的。 |
e.BuildPipeline.PushAssetDependencies: 资源入栈。 BuildPipeline.PopAssetDependencies: 资源出栈。 |
当我们对场景中多个复杂的物体进行打包的适合涉及到资源依赖关系。可以看到,Push和Pos都是成对使用,一个Push/Pop对就相当于一个Layer(层),层可以嵌套,内层可以依赖外层的资源。也就是说内层某资源在打包时,如果其引用的某个资源已经在外层加载了,那么内层的这个资源包就会包含该资源的引用而不是资源本身。Push/Pop实际上维持了一个依赖的堆栈。那么,在加载依赖资源包时,需要注意的是:先加载依赖的资源,然后加载其他资源,需要确保这个顺序。 |
1.单个打包 && 合并打包。 |
using UnityEngine;
using System.Collections;
using UnityEditor;
public class OldAssetBundleEditor : MonoBehaviour {
[MenuItem("AB Editor/Create AssetBunldes Main")]
static void CreateAssetBunldesMain()
{
//获取在Project视图中选择的所有游戏对象
Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
//遍历所有的游戏对象
foreach (Object obj in SelectedAsset)
{
string sourcePath = AssetDatabase.GetAssetPath(obj);
//本地测试:建议最后将Assetbundle放在StreamingAssets文件夹下,如果没有就创建一个,因为移动平台下只能读取这个路径
//StreamingAssets是只读路径,不能写入
//服务器下载:就不需要放在这里,服务器上客户端用www类进行下载。
string targetPath = Application.dataPath + "/StreamingAssets/" + obj.name + ".assetbundle";
if (BuildPipeline.BuildAssetBundle(obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies))
{
Debug.Log(obj.name + "资源打包成功");
}
else
{
Debug.Log(obj.name + "资源打包失败");
}
}
//刷新编辑器
AssetDatabase.Refresh();
}
[MenuItem("AB Editor/Create AssetBunldes ALL")]
static void CreateAssetBunldesALL()
{
Caching.CleanCache();
string Path = Application.dataPath + "/StreamingAssets/ALL.assetbundle";
Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
foreach (Object obj in SelectedAsset)
{
Debug.Log("Create AssetBunldes name :" + obj);
}
//这里注意第二个参数就行
if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, Path, BuildAssetBundleOptions.CollectDependencies))
{
AssetDatabase.Refresh();
}
}
}
我们在Project资源视图栏中同时选中我们刚才制作好的Cube1,Cube2的Prefab。然后在分别点击上图所示的AB Editor栏下的两个按钮。这个时候就会分别生成两个Cube的单个打包和合并打包。不过请注意,一定要保证你的工程Assets目录下有StreamingAssets文件夹。
using UnityEngine;
using System.Collections;
public class OldAssetBundleLoad : MonoBehaviour {
//不同平台下StreamingAssets的路径是不同的,这里需要注意一下。
public static readonly string PathURL =
#if UNITY_ANDROID
"jar:file://" + Application.dataPath + "!/assets/";
#elif UNITY_IPHONE
Application.dataPath + "/Raw/";
#elif UNITY_STANDALONE_WIN || UNITY_EDITOR
"file://" + Application.dataPath + "/StreamingAssets/";
#else
string.Empty;
#endif
void Start()
{
//StartCoroutine(LoadMainGameObject(PathURL + "Cube1.assetbundle"));
//StartCoroutine(LoadMainGameObject(PathURL + "Cube2.assetbundle"));
StartCoroutine(LoadALLGameObject(PathURL + "ALL.assetbundle"));
}
//读取一个资源
private IEnumerator LoadMainGameObject(string path)
{
WWW bundle = new WWW(path);
yield return bundle;
//加载到游戏中
yield return Instantiate(bundle.assetBundle.mainAsset);
bundle.assetBundle.Unload(false);
}
//读取全部资源
private IEnumerator LoadALLGameObject(string path)
{
WWW bundle = new WWW(path);
yield return bundle;
//通过Prefab的名称把他们都读取出来
Object obj0 = bundle.assetBundle.LoadAsset("Cube1");
Object obj1 = bundle.assetBundle.LoadAsset("Cube2");
//加载到游戏中
yield return Instantiate(obj0);
yield return Instantiate(obj1);
bundle.assetBundle.Unload(false);
}
}
2.引入依赖关系的概念。 |
仔细我们可以发现,分开打包的总大小居然是合并打包的2倍。这是为什么呢?其实是这样的:
当选择了BuildAssetBundleOptions.CollectDependencies时,果然你没有将A依赖的资源B使用BuildPipeline.PushAssetDependencies() 和BuildPipeline.PopAssetDependencies()来进行依赖打包,那么A会把其引用的资源都打包到自己的assetbundle 中。如果引用的资源是图片、sprite或自定义的shader(内置的shader不会打包,这里的自定义shader被unity看作是一种资源,打包处理的时候也是如同资源来处理的),那么会打包到assetbundle 中。如果引用的是代码,那么会打包一个对工程中代码的引用,也就是说引用的代码必须存在于工程中,这样当c被加载到本地的时候才可以和本地的代码进行关联,如果本地没有这个代码,则会丢失对这个脚本的引用。 |
那这么说:是不是把所有Prefab都打包到一个AssetBundle里面就是最佳方案么?答案是并不:
1. 更新麻烦:如果所有资源都在一个包下,那么任意一个资源更改了都要把这个包整体更换。 2. 维护麻烦:因为有的物体是共用的某些被依赖项,所以如果涉及到修改这些被依赖项,就会牵一发而动全身。 |
3.依赖打包的流程 |
依赖关系打包的实质就是将那些被依赖的资源先打包 ( 这里我把这类资源用”底层资源”代替 )。对于那些引用了底层资源的资源 ( 这里我把这类资源用”顶层资源”代替 )在打包的时候就不用再将底层资源打包到自己的包里面,而是添加对底层资源的引用,这样就避免了重复打包底层资源了。而且不同资源可以根据项目的分类分别打包到不同的AB包里面,也方便了后期的更新和维护。
废话不多说,我们来了解如何使用依赖关系打包。这里我提供两个依赖关系的示例:
所以,打包方式是从最底层开始:green->Cube1->Cube2,后面两个可以交换顺序。当然仅仅是体现在打包顺序上是不够的,我们这里要引入一个资源栈的概念。一个Push-Pop对应一个资源栈,资源栈可以内部再嵌套多个资源栈。那么我们试图LoadAsset的时候,我们就需要将这个asset所在栈的外部栈的所有asset全部load出来。 |
这里我提供一个我总结的一个小技巧: 1.先把所有材料编号:A-green,B-Cube1,C-Cube2。 2.然后将每个编号两边加上括号,表示每个材料都在一个独立的栈:(A),(B),(C) 3.如果X依赖Y,那么X的栈加入Y的栈里:(A(B)),(A(C))。 4.然后合并:(A(B)(C))。 |
using UnityEngine;
using System.Collections;
using UnityEditor;
public class OldAssetBundleDependence : MonoBehaviour
{
[MenuItem("AB Editor/Create Dependence AssetBunldes")]
public static void Pack()
{
string path = Application.dataPath + "/StreamingAssets";
BuildTarget target = BuildTarget.StandaloneWindows64;
BuildAssetBundleOptions op = BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.DeterministicAssetBundle;
// (
BuildPipeline.PushAssetDependencies();
// A
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Materials/green.mat"), null, path + "/green.assetbundle", op, target);
// (
BuildPipeline.PushAssetDependencies();
// B
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Prefab/Cube1.prefab"), null, path + "/Cube1.assetbundle", op, target);
// )
BuildPipeline.PopAssetDependencies();
// (
BuildPipeline.PushAssetDependencies();
// C
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Prefab/Cube2.prefab"), null, path + "/Cube2.assetbundle", op, target);
// )
BuildPipeline.PopAssetDependencies();
// )
BuildPipeline.PopAssetDependencies();
}
}
清注意,若要使用以上代码请保证:在你的工程目录下也应有此几个资源文件且路径和名字应当一样。
保存代码点击AB Editor/Create Dependence AssetBunldes,就会在StreamingAssets文件夹下生成三个AB包。仔细观察发现和我们最开始的单个打包得到的3个包的区别:
很明显可以看出差别了。所以使用依赖打包可以很大程度上减少资源的重复,减小包的大小。 |
void Start()
{
StartCoroutine(LoadMainGameObject(PathURL + "Cube1.assetbundle"));
}
void Start()
{
StartCoroutine(LoadAB(PathURL + "green.assetbundle"));
StartCoroutine(LoadMainGameObject(PathURL + "Cube1.assetbundle"));
}
public IEnumerator LoadAB(string path)
{
bundle = new WWW(path);
yield return bundle.assetBundle.mainAsset;
}
4.依赖打包的扩展 |
以上就是Unity老版本的AssetBundle打包攻略,接下来我会介绍Unity新版本的AssetBundle使用攻略。
Demo源码地址: 点这里