正所谓:自古套路得人心,学会AssetBundle开发,成就更精简游戏包。
欢迎关注公众号:雷潮课堂
###AssetBundle打包
一、课程内容
1-1游戏套路
1-2什么是AssetBundle
1-3AssetBundle的作用
二、使用AssetBundle打包
2-1版本5.0前后打包
2-2版本5.0前后解压
2-3手动打包版本
三、加载AssetBundle
3-1加载本地AssetBundle(模型,图片)
3-2网络加载AssetBundle(网络加载(UnityWebRequest))
3-3 AssetBundle打包路径问题(不同平台Android、iOS、PC)
四、打包工具的开发
4-1 批量命名打包
4-2 官方Demo案例介绍
1-1、游戏套路
我们经常下载一些游戏App,如果Wifi情况下,App大小就无关紧要。但是如果是流量呢?一看到App的大小,直接就不下了。但是游戏公司怎么会不知道?所以采用热更新,或者直接下载完毕后,再进行加载的行为进行笼络用户。当然这也是产品要求的结果。这里不说游戏的好玩,只讨论这种套路是什么手段进行的。
1-2、什么是AssetBundle?
资源需要打包发布,所以Unity提供的打包策略,也就是AssetBundle。这个的方式有自己的压缩格式(LZMA\压缩),其实就是精简你的资源。简称AB,几乎所有的资源都可以打包程AB,AB可以存放Unity可识别的任何资源类型,具体取决于文件的扩展名。例如:导入的文件后缀为“.byte”,Unity会将这些文件作为文本(TextAssets)导入。导入的文件后缀为“.spine”,Unity会将这些文件作为动画导入。
可以通过官方的Demo来进行学习:Unity5 AssetBundle Demo
1-3、AssetBundle的作用
由于我们要将模型资源放在远程的服务器端,但如果直接放fbx模型是不可以加载的,所以我们可以将fbx做成预设或者是直接将其打包成assetbundle格式的,然后通过www来加载获取。
如果将上述流程反过来,就是加载服务器数据包
2、使用AssetBundle
在打包的时候,可能会重复打包,造成资源包很大。可以将资源拆分细致后,独立打包。
比如:一个模型的网格Mesh,材质Material,贴图Texture.
2-1 Unity5.0之前旧版AB打包
本先扫描所有要打包的资源,然后AssetDatabase.GetDespendencie获得所有的依赖,自己记录起来,由于怕资源名称相同,所以使用AssetDatabase。AssetPathToGUID获得资源的唯一id,然后存起来。
获得所有依赖关系之后,再使用BuildPipeline.PushAssetDependencies和BuildPipeline.PopAssetDependencies按照层级和顺序来打包。这样打出来的资源就完全保留了依赖关系,文件会被拆散,不会重复打包。
2-2 Unity5.0之后,AB打包
BulidPipeline.BuildAssetBundles(outputPath,BuildAssetBundleOptions,BuildTarget)
BuildAssetBundleOptions.None:默认构建AssetBundle的方式。使用LZMA算法压缩,此算法压缩包小,但是加载时间长,而且使用之前必须要整体解压。解压以后,这个包又会使用LZ4算法重新压缩,这样这种包就不要对其整体解压了。(也就是第一次解压很慢,之后就变快了。
BuildAssetBundleOptions.UncompressedAssetBundle:不压缩数据,包大,但是加载很快。
BuildAssetBundleOptions.ChunkBaseCompression:使用LZ4算法压缩,压缩率没有LZMA高,但是加载资源不必整体解压。这种方法中规中矩,我认为比较常用。
以上是常用的三种,接下来会对你其余的几种做简单的介绍
BuildAssetBundleOptions.DisableWriteTypeTree:不会在AssetBundle中包含类型信息。
BuildAssetBundleOptions.DeterministicAssetBundle:使用存储在Asset Bundle中的对象的id的哈希构建Asset Bundle。
BuildAssetBundleOptions.ForceRebuildAssetBundle:强制重建Asset Bundles。
BuildAssetBundleOptions.IgnoreTypeTreeChanges:执行增量构建检查时忽略类型树更改。
BuildAssetBundleOptions.AppendHashToAssetBundleName:将哈希附加到assetBundle名称。
BuildAssetBundleOptions.StrictMode:如果在其中报告任何错误,则不允许构建成功。
BuildAssetBundleOptions.DryRunBuild:不实际构建它们。
BuildAssetBundleOptions.DisableLoadAssetByFileName:通过文件名禁用Asset Bundle的加载。
BuildAssetBundleOptions.DisableLoadAssetByFileNameWithExtension:通过带扩展名的文件名禁用Asset Bundle 的加载。
StandaloneWindows: 打包32位windows平台上的包。
StandaloneWindows64: 打包64位windows平台上的包。
iOS: 打包iOS平台上的包。
Android : 打包Android平台上的包。
每一个资源可以设置一个assetBundleName。只要调用这个方法,那么所有已经设置过AB的资源,就会自动打包。
2-3、手动打包版本
3-1 加载AssetBundle 这里要使用编辑器开发,请点击另一篇文章
设置保存路径public class AssetBundle : Editor{[MenuItem("Tools/CreatAssetBundle")]public static void CreatAssetBundle(){string filePath = "AssetBundle"; // 文件名为“AsssetBundle”if (Directory.Exists(filePath) == false) // 判断是否存在,不存在创建{Directory.CreateDirectory(filePath); // 根据文件夹路径创建文件夹} // 可以使用这个ApI (打包输出的路径,压缩格式(枚举),编译平台)BuildPipeline.BuildAssetBundles(filePath, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);}}
加载模型
// 加载模型AssetBundle ab = AssetBundle.LoadFromFile("AssetBundle/cube.unity");GameObject go = ab.LoadAsset<GameObject>("Cube");GameObject cube = Instantiate(go);
加载图片
if (img == null) // 如果Img没有赋值{img = GameObject.Find("Image").GetComponent<Image>(); // 寻找图片所在的物体,并获取身上的组件Image}AssetBundle ab = AssetBundle.LoadFromFile("AssetBundle/img"); // 加载AB资源包Sprite s = ab.LoadAsset<Sprite>("1213"); // 加载资源包中的1212图片img.sprite = s; //将加载的图片进行赋值
3-2、网络加载AssetBundle(UnityWebRequest)
1.引用using working.
2. - UnityWebRequest.GetAssetBundle(URL)获取assetBundle资源,返回资源的函数SendWebRequest()
- DownloadHandlerAssetBundle.GetContent()获取assetBundle资源包
- LoadAsset<>()加载,实例化。
void Start () { StartCoroutine(Load()); }private IEnumerator Load(){string url = "";//此为AssetBundle资源路径,可为本地,也可以是服务端UnityWebRequest request= UnityWebRequest.GetAssetBundle(url);yield return request.SendWebRequest ();// AssetBundle ab = DownloadHandlerAssetBundle.GetContent (request );AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;GameObject ao = ab.LoadAsset<GameObject>("Cube");Instantiate(ao);}
加载音乐
IEnumerator LoadABWeb(){UnityWebRequest request = UnityWebRequest.GetAssetBundle(path);yield return request.SendWebRequest();Debug.Log(request.error);AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);audio.clip = bundle.LoadAsset<AudioClip>("music01");audio.Play();}
3-3、AssetBundle打包路径问题(不同平台Android、iOS、PC)
官方的讲解
1.首先要讲一下不同平台下的一个StreamingAssets路径,这是不同的。
//不同平台下StreamingAssets的路径是不同的,这里需要注意一下。public static readonly string PathURL =#if UNITY_ANDROID //安卓"jar:file://" + Application.dataPath + "!/assets/";#elif UNITY_IPHONE //iPhoneApplication.dataPath + "/Raw/";#elif UNITY_STANDALONE_WIN || UNITY_EDITOR //windows平台和web平台"file://" + Application.dataPath + "/StreamingAssets/";#elsestring.Empty;#endif
这就获取到了不同平台的一个路径,我们可以将打包的文件放在这些路径下,然后再从这路径去读取资源,前提要手动创建一个StreamingAssets文件夹
2.关于打包assetbundle的脚本
using UnityEngine;using System.Collections;using UnityEditor;public class Test : Editor{//打包单个[MenuItem("Custom Editor/Create AssetBunldes Main")]static void CreateAssetBunldesMain (){//获取在Project视图中选择的所有游戏对象Object[] SelectedAsset = Selection.GetFiltered (typeof(Object), SelectionMode.DeepAssets);//遍历所有的游戏对象foreach (Object obj in SelectedAsset) {//本地测试:建议最后将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("Custom 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 ();} else {}}[MenuItem("Custom Editor/Create Scene")]static void CreateSceneALL (){//清空一下缓存Caching.CleanCache();string Path = Application.dataPath + "/MyScene.unity3d";string []levels = {"Assets/Level.unity"};//打包场景BuildPipeline.BuildPlayer( levels, Path,BuildTarget.WebPlayer, BuildOptions.BuildAdditionalStreamedScenes);AssetDatabase.Refresh ();}}
3.读取资源,这里只举例从本地读取,跟从网络读取是一样的,可以参考官方文档:
本地读取
using UnityEngine;using System.Collections;public class MyAssetBundleRun : MonoBehaviour{//不同平台下StreamingAssets的路径是不同的,这里需要注意一下。public static readonly string PathURL =#if UNITY_ANDROID"jar:file://" + Application.dataPath + "!/assets/";#elif UNITY_IPHONEApplication.dataPath + "/Raw/";#elif UNITY_STANDALONE_WIN || UNITY_EDITOR"file://" + Application.dataPath + "/StreamingAssets/";#elsestring.Empty;#endifvoid OnGUI(){if(GUILayout.Button("Main Assetbundle")){//StartCoroutine(LoadMainGameObject(PathURL + "Prefab0.assetbundle"));//StartCoroutine(LoadMainGameObject(PathURL + "Prefab1.assetbundle"));StartCoroutine(LoadMainCacheGameObject(PathURL + "Prefab0.assetbundle"));StartCoroutine(LoadMainCacheGameObject(PathURL + "Prefab1.assetbundle"));}if(GUILayout.Button("ALL Assetbundle")){StartCoroutine(LoadALLGameObject(PathURL + "ALL.assetbundle"));}if(GUILayout.Button("Open Scene")){StartCoroutine(LoadScene());}}//读取一个资源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.Load("Prefab0");Object obj1 = bundle.assetBundle.Load("Prefab1");//加载到游戏中yield return Instantiate(obj0);yield return Instantiate(obj1);bundle.assetBundle.Unload(false);}private IEnumerator LoadMainCacheGameObject(string path){WWW bundle = WWW.LoadFromCacheOrDownload(path,5); yield return bundle; //加载到游戏中yield return Instantiate(bundle.assetBundle.mainAsset); bundle.assetBundle.Unload(false);}private IEnumerator LoadScene(){WWW download = WWW.LoadFromCacheOrDownload ("file://"+Application.dataPath + "/MyScene.unity3d", 1);yield return download;var bundle = download.assetBundle;Application.LoadLevel ("Level");}}
4-1、批量命名自动打包
项目中的资源涉及方方面面,我们不可能每个都进行修改名字并打包,所以需要一个工具,来帮助我们批量命名自动打包
这里是核心代码块,也是游戏核心开发人员的必备技能涉及自定义编辑器工具模块,可以在最下方购买哦我们的课程。
4-2 官方Demo案例介绍
可以加群134688909 将Demo下载下来,因为接下来全部使用这个进行。我们可以测试一下打包成程序
会输出一个文件,你可以选择一个文件夹进行输出。
我们实际这样做了,发现输出控制台有如下输出
我们可以将寻找一下是那个代码中输出的这个话
顺藤摸瓜之后其实我们发现就是我们的当前项目中的场景没有加载进去
运行后,发现与我们手动打包出来的程序一模一样,也就是说我们可以程序的手段进行编译打包。那么这个代码在哪?我们是不是可以直接使用呢?
StreamingAssets它下面的所有资源不会被加密,然后是原封不动的打包到发布包中
然后我们就可以开始玩耍游戏中的所有场景了,因为资源已经OK了。可以寻找并加载了。
欢迎购买本课程:
腾讯课堂
网易云课堂
如果觉得《Unity资源打包(一):AssetBundle使用-更新》对你有帮助,请点赞、收藏,并留下你的观点哦!