打包AssetBundle思路
1.通常把项目中用到的所有Shader打到一个ab包里,在资源调用时首先加载所有Shader,因为项目中很多资源引用了Shader;
2.把一些共同引用的资源打到同一个包里,比如UIA用了materialC,UIB也用了materialC,UIA,UIB还用到了TexC,那么我们把materialC,TexC打到同一个包里,我们使用UIA或UIB时首先加载他们的引用包(也就是materialC和TexC所在的AB包)
3.然后所有Lua脚本类的打到同一个包里面
4.所有的字体可以打成同一个包,所有的例子特效单独一个包;
AssetBundle的加载与卸载管理
加载AssetBundleManifest
一些重要信息都在AssetBundleManifest,比如资源依赖,路径等信息,所以加载AssetBundle前,先要记载读取AssetBundleManifest的信息,读取完之后就没用了,我们把它卸载掉,节省内存空间
AssetBundle abManifestBundle = AssetBundle.LoadFromFile(GetFullLoadAbPath("AssetBundles"));
abManifest = abManifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
abManifestBundle.Unload(false);
加载相关AssetBundle
我们从目标AssetBundle包里加载Asset进行实例化的时候,首先检查这个AB资源包的引用,先加载引用
比如UIA用了materialC,UIB也用了materialC,UIA,UIB还用到了TexC,那么我们把materialC,TexC打到同一个包里,我们使用UIA或UIB时首先加载他们的引用包(也就是materialC和TexC所在的AB包)
,当所有的相关应用加载完毕,再加载目标AssetBundle,最后LoadAsset我们所需要的打包在该AB包里面的内容。
但是这样存在一个问题,就是一个AB包里可能有很多资源,我们加载这些资源的时候,可能会出现重复加载同一个AssetBundle包的情况,这很费时间,所以我们要把加载过的AssetBundle存在内存中,每次加载AB包时判断该AB包是否已经加载过了,如果加载过了,那么它是被我们保存在内存中了,我们直接在内存中读取,这样会快很多。
public AssetBundle LoadAssetBundle(string resPath, bool unloadbundle = false)
{
resPath = resPath.ToLower();
// string abPath = resPath.Replace("/", "_");
string abPath = resAbMap[resPath];
if (!cacheMap.ContainsKey(abPath) || (cacheMap[abPath].request != null &&
cacheMap[abPath].request.assetBundle == null))
{
List<string> deps = GetAllDependencies(abPath);
bool depAllLoaded = true;
for (int i = 0; i < deps.Count; i++)
{
if (!cacheMap.ContainsKey(deps[i]) || (cacheMap[deps[i]].request != null && cacheMap[deps[i]].request.assetBundle == null))
{
AssetBundle depAb = AssetBundle.LoadFromFile(GetFullLoadAbPath(deps[i]));
if (cacheMap.ContainsKey(deps[i]))
{
cacheMap[deps[i]].assetBundle = depAb;
}
else
{
cacheMap[deps[i]] = new AssetBundleCacheInfo(null, depAb);
}
if (depAb == null)
{
depAllLoaded = false;
break;
}
}
}
if (depAllLoaded)
{
string fullPath = GetFullLoadAbPath(abPath);
AssetBundle needLoadBundle = AssetBundle.LoadFromFile(fullPath);
if (needLoadBundle != null)
{
if (cacheMap.ContainsKey(abPath))
{
cacheMap[abPath].assetBundle = needLoadBundle;
}
else
{
cacheMap[abPath] = new AssetBundleCacheInfo(null, needLoadBundle);
}
}
else
{
Debug.LogWarning("load ab fail:" + fullPath);
}
}
}
if (cacheMap.ContainsKey(abPath))
{
if (cacheMap[abPath].assetBundle == null)
{
if (cacheMap[abPath].request != null)
{
cacheMap[abPath].assetBundle = cacheMap[abPath].request.assetBundle;
}
}
return cacheMap[abPath].assetBundle;
}
else
{
return null;
}
}
加载资源
为了加快加载资源的速度,我们同样也将已经加载过的资源保存在内存中,加载之间判断内存中是否存在,存在则直接读取内存中的资源,不存在则加载资源然后将其保存在内存中,供下次读取。
我们每次加载资源时,都先要加载其所在的AssetBundle包,并且要记下加载资源AB包被引用的次数,这样方便我们在卸载AssetBundle时,检测当前这个要卸载的AssetBUndle包还有没有资源引用它,如果没有资源引用,我们才启用UnLoad卸载该AssetBundle
未完待续…