微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Unity打界面预设资源增量包,如何剥离图集依赖,以及什么情况下适合剥离图集依赖

软件环境:

win7操作系统。
Unity5.5.5p2,使用NGUI插件

工程目录

在这里插入图片描述


如上,图集放在GameRes/Atlas目录中,界面预设放在GameRes/UIPanel目录中。
界面预设MainPanel依赖图集Atlas1Atlas2

发布app版本时打AssetBundle

发布app版本的时候,把资源打AssetBundle放在StreamingAssets目录中。
规则:
GameRes/Atlas目录打成一个AssetBundle:atlas.ab
GameRes/UIPanel目录打成一个AssetBundle:uipanel.ab
注意,是构造AssetBundleBuild[]数组,然后执行一次BuildPipeline.BuildAssetBundles接口,
如果atlas.abuipanel.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.abmainpanel.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的时候,剥离Atlas1Atlas2的依赖,但不剥离Atlas3的依赖。
代码和上面的剥离图集依赖的基本一致,这里就不写了。这样打出来的MainPanel又小,又可以直接显示新加的精灵图。
不过因为是这样新开了一个图集,所以没法和原来的Atlas2合并批次,会导致DarwCall升高,所以这种做法也不是无上限的,要综合评估。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐