上一篇《Unity 包体如何缩减优化(一)》我们讨论了Resouces文件夹的缩减以及纹理格式的缩减,这一篇将讨论余下的内容。
如果我们游戏内有很多的小图片,又不能比4整除,也不是2的N次方,这样就算我们把它们设置成ETC2 8bits 也无济于事,unity在构建过程中会自动变为RGBA32或RGBA16。要避免这种情况出现,我们可以这么做
1、按被4整除或2的次方制作贴图
2、打图集
被4整除好理解,图片宽高整除4就可以了,我们重点讨论一下图集。
图集简单来说有两个优点,一是将各种小图打包到一张符合规则的大图中,相对来说可以缩减一小部分包体,二是可以减少大部分Drawcall,提升性能。下面我们讨论一下如何打图集:
点击Edit 菜单,打开Project Settings 窗口,如下图:
上面这个设置是开启图集功能,开启后可以创建图集,如下图:
创建完图集,可以将要打包的图片放进去,如下图:
这样一个图集就打好了,但每次都手动这么操作,显然也是不明智的,我们还是要提倡自动化。下面我们通过脚本来自动生成图集,如下:
打开我们上篇的贴图管理器,添加如下代码:
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.U2D;
using UnityEngine.U2D;
using UnityEngine;
namespace EditorAsset
{
/// <summary>
/// 贴图管理器
/// </summary>
public class AssetTextureMgr
{
private static int _maxAltalSize = 2048;
//按文件夹创建图集,不包括子文件夹
public static void CreateAtlas(string dir)
{
var files = AssetDir.GetAssetChildePath(dir, new string[] { ".png" }, null);
if (files.Length > 0)
{
var packSettting = new SpriteAtlasPackingSettings();
packSettting.enableRotation = true;
packSettting.padding = 4;
packSettting.enableTightPacking = false;
packSettting.blockOffset = 1;
packSettting.enableAlphaDilation = true;
var textureSetting = new SpriteAtlasTextureSettings();
textureSetting.sRGB = true;
textureSetting.filterMode = UnityEngine.FilterMode.Bilinear;
var androidSettings = new TextureImporterPlatformSettings();
androidSettings.name = "Android";
androidSettings.overridden = true;
androidSettings.maxTextureSize = _maxAltalSize;
androidSettings.format = _androidAlphaDefaultFormat;
var iosSetting = new TextureImporterPlatformSettings();
iosSetting.name = "iPhone";
iosSetting.overridden = true;
iosSetting.maxTextureSize = _maxAltalSize;
iosSetting.format = _iosDefaultFormat;
var atlas = new SpriteAtlas();
atlas.IsIncludeInBuild();
atlas.SetPackingSettings(packSettting);
atlas.SetTextureSettings(textureSetting);
atlas.SetPlatformSettings(iosSetting);
atlas.SetPlatformSettings(androidSettings);
var atlasName = Path.GetFileName(dir);
var altasFile = Path.Combine(dir, atlasName + ".spriteatlas");
var sprites = new List<Sprite>();
foreach (var f in files)
{
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(f);
if(sprite != null )
{ sprites.Add(sprite); }
}
if(sprites.Count > 0)
atlas.Add(sprites.ToArray());
AssetDatabase.CreateAsset(atlas, altasFile);
AssetDatabase.SaveAssets();
Selection.activeObject = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(altasFile);
}
}
//按文件夹创建图集,包括所有子文件夹
public static void CreateAtlasAndChilde(string dir)
{
var dirs = AssetDir.GetAssetDir(dir, null);
foreach (var d in dirs)
{
CreateAtlas(d);
}
}
}
}
这样我们创建图集的代码就OK了,下面我们再做一个菜单功能,只要点击某个文件夹就可以将该文件夹下面的图片全部打包进图集,如下:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
namespace EditorAsset
{
public class AssetTextureAutomation
{
[MenuItem("Assets/刷新TextureSettings")]
private static void RefreshTextureSettings()
{
var dir = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
var files = AssetDir.GetAssetPath(dir, new string[] { ".png" }, null, null);
foreach (var f in files)
{
AssetTextureMgr.SetAndroidSettings(f);
AssetTextureMgr.SetIosSettings(f);
}
Debug.Log($"----------Fresh settings ok. count {files.Length}");
}
[MenuItem("Assets/刷新TextureSettings", true)]
private static bool IsSelected1()
{
return Selection.assetGUIDs != null && Selection.assetGUIDs.Length > 0;
}
[MenuItem("Assets/创建和刷新Atlas")]
private static void CreateAtlas()
{
var dir = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
AssetTextureMgr.CreateAtlas(dir);
Debug.Log($"----------Create atlas ok, name {Path.GetFileName(dir)}");
}
[MenuItem("Assets/创建和刷新Atlas", true)]
private static bool IsSelected2()
{
return Selection.assetGUIDs != null && Selection.assetGUIDs.Length > 0;
}
[MenuItem("Assets/创建和刷新所有Atlas")]
private static void RefreshAtlas()
{
var dir = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
AssetTextureMgr.CreateAtlasAndChilde(dir);
}
[MenuItem("Assets/创建和刷新所有Atlas", true)]
private static bool IsSelected3()
{
return Selection.assetGUIDs != null && Selection.assetGUIDs.Length > 0;
}
}
}
最终的效果如下图所示:
自动化操作下来,效果是不是杠杠的呢。
做完这一步,纹理的缩减优化基本上告一段落了。下面我们继续讨论代码和引用库的缩减。
三、代码、引用库的缩减
代码和引用库,Unity会自动分析引用和依赖关系,将要用到的代码库等打进包体,没用到的剥离。根据这一原则,我们可以做以下优化:
1、将没用的包删除(保险一点),如下图:
这部分插件包,有些我们项目根本不会用到的,要删掉。如果不删除,unity会把代码和插件内的贴图都会打进去,无端端的多了几百K甚至几M,不值得。如timeline包,如果项目内不会用到,unity还是会打包进去,打开打包日志就可以查看到记录。
2、发布平台时,指定目标架构,这一点可以省不少,如下图:
3、代码裁剪
如果前面所有的步骤都操作完了,还是没有达到缩减要求,可以考虑代码裁剪。代码裁剪有一定的要求和风险,建议大家谨慎操作。一般情况下做完上面提到的要点,包体基本上符合要求了,在此代码裁剪就不再展开讨论。
笔者经过文章中一系列的操作,成功将包体从120多M缩减到70M左右,如下图所示。其实还有继续缩减的空间,如重复资源的打包策略,图集的打包策略等,这些都和包体大小有关。
(完)