一.简单的打包实现(打包游戏物体)。
1.将需要打包的游戏物体制作成预制体,在预制体的Inspector面板最下方找到AssetBundle选项,在这里设置物体打包后的包名和后缀。名称为None代表不打包。
2.添加打包脚本,脚本不需要继承Monobehavior。在菜单栏上添加打包选项。
using System.IO; using UnityEditor; public class CreateAssetBundles { //使用一个静态方法进行打包,将这个方法添加到菜单栏 [MenuItem("Assets/Build AssetBundles")] static void BuildAllAssetBundles() { //因为打包时不会自动创建路径,所以检验打包路径是否存在,不存在需要先创建打包路径 string dir = "AssetBundles"; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } //打包 BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64); } }
3.打包
4.在刚才设置的打包文件夹下可以查看是否打包成功
二.资源的加载
1.添加空物体,挂载一个用于加载资源的脚本
2.在脚本中加载资源
public class LoadFromFileExample : MonoBehaviour { // Start is called before the first frame update void Start() { //加载资源,加载后的内容保存为AssetBundle对象 AssetBundle assetBundle = AssetBundle.LoadFromFile("AssetBundles/wall.unity3d"); //取出资源,资源的类型时GameObject,名称是Wall GameObject wallPrefab = assetBundle.LoadAsset<GameObject>("Wall"); //实例化取出的游戏物体 Instantiate(wallPrefab); } }
三.更多的打包和加载资源的选择
1.打包目录划分:在unity中的Inspector窗口下确定填写打包后包名时可以通过"/"进行目录划分。不同的资源可以指定相同的包名和后缀,也就是同一个包中可以包含多个资源。
2.AssetBundle分组策略:可以采用按照逻辑实体分组、按照类型分组、按照使用分组等分组策略,根据项目的实际需求确定具体的分组策略。通常遵循以下分组原则:
1)把经常更新的资源和不常更新的资源分开,减少包的大小
2)把需要同时加载的资源放在一起,提高加载效率
3)把和其他包共享的资源单独放置,避免重复打包
4)把一些需要同时加载的小资源放在一起,提高加载效率
5)可以通过后缀区分同一个资源的不同版本
3.BuileAssetBundleOptions选项
官方API:
常用选项:
1)BuildAssetHBundleOptions.None:默认使用LZMA算法压缩。
2)BuileAssetBundleOptions.UncompressedAssetBundle:不压缩
3)BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4压缩
LZMA压缩和LZ4压缩:
LZMA压缩比LZ4压缩后的包体积更小,压缩率更高,但是也意味着解压缩的时间更长,加载时间更长。而且LZMA压缩在解压缩时只能整体解压,如果只是想使用压缩文件中的一小部分内容的话会造成资源浪费,因此一般在下载时使用LZMA压缩算法,下载后再使用LZ4算法保存到本地。
4.minifest文件详解
5.加载AssetBundle的其他方式
1)AssetBundle.LoadFromMemoryAsync方法:加载二进制字节数组
异步的方式
IEnumerator Start() { AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes("AssetBundles/wall.unity3d")); yield return request; AssetBundle ab = request.assetBundle; GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall"); Instantiate(wallPrefab); }
同步的方式
void Start() { AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes("AssetBundles/wall.unity3d")); GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall"); Instantiate(wallPrefab); }
2)AssetBundle.LoadFromFile方法:直接从文件加载
异步的方式
IEnumerator Start() { AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync("AssetBundles/wall.unity3d"); yield return request; AssetBundle ab = request.assetBundle; GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall"); Instantiate(wallPrefab); }
同步的方式
void Start() { AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/wall.unity3d"); GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall"); Instantiate(wallPrefab); }
3)WWW.LoadFromCacheOrDownload方法:从服务器或本地缓存加载(即将弃用)
IEnumerator Start() { while (!Caching.ready) { yield return null; } WWW www = WWW.LoadFromCacheOrDownload(@"file:\D:UnityProjectsAssetBundleLearningAssetBundleswall.unity3d", 1); AssetBundle ab = www.assetBundle; GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall"); Instantiate(wallPrefab); }
4)UnityWebRequestAssetBundle方法:从服务器加载(UnityWebRequest方法弃用)
IEnumerator Start() { UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri: @"file:\D:UnityProjectsAssetBundleLearningAssetBundleswall.unity3d"); yield return request.SendWebRequest(); AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request); GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall"); Instantiate(wallPrefab); }
IEnumerator Start() { UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri: @"file:\D:UnityProjectsAssetBundleLearningAssetBundleswall.unity3d"); yield return request.SendWebRequest(); AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle; GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall"); Instantiate(wallPrefab); }
6.manifest文件的加载
void Start() { //加载manifest文件 AssetBundle manifestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles"); AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); //获取所有包名称 foreach(string name in manifest.GetAllAssetBundles()) { print(name); } }
void Start() { //加载manifest文件 AssetBundle manifestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles"); AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); //获取"wall.unity3d"这个包的所有依赖 foreach (string name in manifest.GetAllDependencies("wall.unity3d")) { print(name); //加载依赖文件 AssetBundle.LoadFromFile("AssetBundles/" + name); } }
7.卸载AssetBundle包
使用AssetBundle.Unload(false)
或AssetBundle.Unload(true)
来卸载资源,参数代表是否将正在使用中的已加载资源一并卸载。但是需要注意的是,如果使用AssetBundle.Unload(false)
卸载资源,正在使用中的资源没有被卸载,这些正在使用中的资源就会一直占用内存,为避免内存被一直占用,一般使用AssetBundle.Unload(true)
卸载资源,如果一定要使用AssetBundle.Unload(false)
卸载资源,可以在合适的时间调用Resources.UnloadUnusedAssets卸载资源或者以非附加的形式加载场景,这样会自动调用Resources.UnloadUnusedAssets卸载资源。
8.文件校验
校验文件通常有CRC、MD5、SHA1三种算法生成校验值,可以从manifest文件中看到,AssetBundle使用的是CRC算法生成校验码。
9.常见问题
1)依赖包重复问题
解决:把共享的资源一起打包/根据使用时间分割包/共享的部分打包到一起
2)图集重复问题