最近在做优化游戏内存的工作,当然也就涉及到最重要的资源的加载释放。特此记录一下踩过的坑以及一些注意事项。关于AssetBundle的概念网上已经有很多资料了,这里就不提了。
1.打AB包的时候,用何种方式压缩AB?
现目前主要用3种不同的方式来打ab包:lzma压缩, lz4压缩,不压缩,以下分别对3种打包策略进行试验。
试验打包对象为一张1024*1024的图集对象,用了ETC2进行压缩。
打包代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; public class Tools : Editor { private static List<AssetBundleBuild> maps = new List<AssetBundleBuild>(); [MenuItem("MyMenu/Build Assetbundle")] static private void BuildAssetBundle() { maps.Clear(); string dir = Application.dataPath + "/StreamingAssets"; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } string spriteSetDir = Application.dataPath + "/SpriteSet"; string[] dirs = Directory.GetDirectories(spriteSetDir, "*", SearchOption.AllDirectories); for (int i = 0; i < dirs.Length; i++) { string name = dirs[i].Replace(spriteSetDir, string.Empty); name = "SpriteSet/" + name.ToLower() + ".unity3d"; string path = "Assets" + dirs[i].Replace(Application.dataPath, ""); AddBuildMap(name, "*.png", path); } BuildPipeline.BuildAssetBundles(dir, maps.ToArray(), BuildAssetBundleOptions.None, BuildTarget.Android); } static void AddBuildMap(string bundleName, string pattern, string path) { string[] files = Directory.GetFiles(path, pattern); if (files.Length == 0) return; for (int i = 0; i < files.Length; i++) { files[i] = files[i].Replace('\\', '/'); } AssetBundleBuild build = new AssetBundleBuild(); build.assetBundleName = bundleName; build.assetNames = files; maps.Add(build); } }加载ab测试代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Diagnostics; public class Loader : MonoBehaviour { // Use this for initialization void Start () { System.Diagnostics.Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); // 开始监视代码运行时间 //code AssetBundle assetbundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/spriteset/sprite_boss_baiguiju.unity3d"); stopwatch.Stop(); // 停止监视 System.TimeSpan timespan = stopwatch.Elapsed; UnityEngine.Debug.Log("C# costTime:" + timespan.TotalMilliseconds); double hours = timespan.TotalHours; // 总小时 double minutes = timespan.TotalMinutes; // 总分钟 double seconds = timespan.TotalSeconds; // 总秒数 double milliseconds = timespan.TotalMilliseconds; // 总毫秒数 } // Update is called once per frame void Update () { } }
1.1打包结果以及加载速度对比
由于时间有限,仅限于window测试,下来有空的时候在真机上测试一下。
压缩方式 | ab包容量 | 加载消耗时间 | |
BuildAssetBundleOptions.None lzma压缩 | 180 KB | 13.4731ms | |
BuildAssetBundleOptions.ChunkBasedCompression lz4压缩 | 217 KB | 0.8209ms | |
BuildAssetBundleOptions.UncompressedAssetBundle 不压缩 | 1M | 0.7838ms |
2.AssetBundle.Unload注意事项。
例如某个UI 打成了AB包 a.unity3d ,该资源引用某图集b.unity3d。
2.1重构起始做法(伪代码)
AssetBundle ab_a = LoadAssetbundle(a.unity3d)//同时递归加载了依赖 b.unity3d ab_b
GameObject prefab = ab_a.load() as GameObject;
GameObject ui= Instantiate(prefab) as GameObject;
扫描二维码关注公众号,回复:
1552794 查看本文章
SetUiInfo();
ab_a.Unload(false) ; //同时递归也让ab_b卸载掉。
2.2问题所在
这种做法的结果是 UI 上很多image图片错乱,明显是Image没正确加载到Sprite。一番纠结之后得出结论是
Instantiate 操作并不是立即完成,需要有几帧的时间才能加载完成。
2.3正确做法,不一定好,有更好的方案望赐教。
开启协程,让加载ab完成后1秒在执行卸载操作。