文章目录
软件环境:
win7操作系统。
Unity5.5.5p2,使用NGUI插件。
工程目录
如上,图集放在
GameRes/Atlas
目录中,界面预设放在GameRes/UIPanel
目录中。界面预设
MainPanel
依赖图集Atlas1
和Atlas2
。
发布app版本时打AssetBundle
发布app版本的时候,把资源打AssetBundle放在StreamingAssets
目录中。
规则:GameRes/Atlas
目录打成一个AssetBundle:atlas.ab
。GameRes/UIPanel
目录打成一个AssetBundle:uipanel.ab
。
注意,是构造AssetBundleBuild[]
数组,然后执行一次BuildPipeline.BuildAssetBundles
接口,
如果atlas.ab
和uipanel.ab
是分别执行两次BuildPipeline.BuildAssetBundles
接口打出来的,那uipanel.ab
会很大,它包含了atlas.ab
的资源,这样就造成了AssetBundle冗余,相当于包内有两份图集副本。
当然,你也可以只打uipanel.ab
,图集不用打,因为已经包含在uipanel.ab
,不过就是颗粒度太大,不便于分块进行加载。
打AssetBundle代码大致如下:
[MenuItem("Tools/BuildGameResAssetBundles")]
public static void BuildAssetBundleInRes()
{
BuildAssetBundleByDir(new string[] { "Atlas", "UIPanel" }, "res");
}
static void BuildAssetBundleByDir(string[] dirs, string outputPath)
{
var dirCnt = dirs.Length;
var builders = new AssetBundleBuild[dirCnt];
for (int i = 0; i < dirCnt; ++i)
{
var dir = dirs[i];
var fullDir = Application.dataPath + "/GameRes/" + dir;
var fs = Directory.GetFiles(fullDir);
var fsCnt = fs.Length;
builders[i].assetBundleName = dir + ".ab";
string[] assetNames = new string[fsCnt];
for (int j = 0; j < fsCnt; ++j)
{
assetNames[j] = fs[j].Replace(Application.dataPath, "Assets");
}
builders[i].assetNames = assetNames;
}
BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath + "/" + outputPath, builders, BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.StandaloneWindows64);
AssetDatabase.Refresh();
}
运行时加载AssetBundle
运行时,从StreamingAssets
目录中加载AssetBundle,现在假设我们想要展示MainPanel
这个界面预设,很明显,我们要加载uipanel.ab
,但是,uipanel.ab
依赖atlas.ab
,所以必须先加载atlas.ab
,然后再加载uipanel.ab
,然后再从uipanel.ab
中加载MainPanel
并实例化展示出来。
代码大致如下:
AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/res/atlas.ab");
var uipanelAb = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/res/uipanel.ab");
var mainPanelPrefab = uipanelAb.LoadAsset<GameObject>("MainPanel");
var panelObj = Instantiate(MainPanelPrefab);
打界面预设增量包
情况一. 图集不加新精灵图,只是调整界面元素(剥离图集依赖)
app已经在线上运营,突然策划要求热更MainPanel
界面,界面上的精灵图的坐标要
调整一下。这种情况可以剥离图集依赖。
如何剥离图集依赖?
构造一个AssetBundleBuild[]
数组,把GameRes/Atlas
目录中的图集和MainPanel
塞进去,执行一次BuildPipeline.BuildAssetBundles
接口,打出来的AssetBuble为atlas.ab
和mainpanel.ab
,并且mainpanel.ab
很小,因为mainpanel.ab
依赖atlas.ab
,但因为atlas.ab
已经在包内,所以atlas.ab
不需要作为增量包,只需一个小小的mainpanel.ab
即可。
代码大致如下:
static void BuildUpdateAssetBundlesWithoutAtlas()
{
var objects = Selection.objects;
var len = objects.Length;
AssetBundleBuild[] builders = new AssetBundleBuild[len + 1];
for (int i = 0; i < len; ++i)
{
var obj = objects[i];
var assetPath = AssetDatabase.GetAssetPath(obj);
{
builders[i].assetBundleName = obj.name + ".ab";
builders[i].assetNames = new string[] { assetPath };
}
}
// 图集AssetBundle
builders[len].assetBundleName = "atlas.ab";
var fs = Directory.GetFiles(Application.dataPath + "/GameRes/Atlas");
var fsCnt = fs.Length;
string[] assetNames = new string[fsCnt];
for (int j = 0; j < fsCnt; ++j)
{
assetNames[j] = fs[j].Replace(Application.dataPath, "Assets");
}
builders[len].assetNames = assetNames;
BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath + "/update", BuildTarget.StandaloneWindows64);
// 删除图集的AssetBundle
File.Delete(Application.streamingAssetsPath + "/update/atlas.ab");
AssetDatabase.Refresh();
}
情况二. 在已有的图集要加新精灵图,预设界面要显示这个新的精灵图(不剥离图集依赖)
app在线上运营着,突然,策划又要求热更MainPanel
界面,要加个新的精灵图并显示在界面上,
精灵图打在原来的Atlas2
中,这个时候如果还用上的方式剥离图集依赖,那么MainPanel
界面上这个新加的精灵图就显示不出来了。
除非,你把Atlas2
也单独打一份AssetBundle,然后用代码动态加载Atlas2
,并把MainPanel
界面中的精灵图赋值为新加的这个精灵图,条条大路通罗马,这种方式是可以的,不过我这里要讲的是不剥离图集依赖的做法:构造一个AssetBundleBuild[]
数组,但是数组长度为1,只塞入MainPanel
预设,这打出来的mainpanel.ab
就包含了Atlas2
(也会包含Atlas1
),缺点是文件会比较大,并且加载进内存后,内存中相当于有两个Atlas2
副本,造成内存冗余,所以这种方式不大建议,但如果执意要这么做,也没有什么太大问题。
不剥离AssetBundle的代码大致如下:
static void BuildUpdateAssetBundlesWithAtlas()
{
var objects = Selection.objects;
var len = objects.Length;
AssetBundleBuild[] builders = new AssetBundleBuild[len + 1];
for (int i = 0; i < len; ++i)
{
var obj = objects[i];
var assetPath = AssetDatabase.GetAssetPath(obj);
{
builders[i].assetBundleName = obj.name + ".ab";
builders[i].assetNames = new string[] { assetPath };
}
}
BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath + "/update", BuildTarget.StandaloneWindows64);
AssetDatabase.Refresh();
}
情况三. 创建新图集,预设界面要显示这个新新图集的精灵图(部分剥离图集依赖)
如果新加的精灵图不打在Atlas2
中,而是新开一个全新的图集Atlas3
,那么就可以在打MainPanel
的AssetBundle的时候,剥离Atlas1
和Atlas2
的依赖,但不剥离Atlas3
的依赖。
代码和上面的剥离图集依赖的基本一致,这里就不写了。这样打出来的MainPanel
又小,又可以直接显示新加的精灵图。
不过因为是这样新开了一个图集,所以没法和原来的Atlas2
合并批次,会导致DarwCall
升高,所以这种做法也不是无上限的,要综合评估。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。