被Hugo的更新弄得很伤,所以搬运下github上的博客
UI方面的工作比较碎,比较单调,但也有很多讲究,合理的UI设计可以节省很多DrawCall和CPU的开销,这里总结一些Tips。
需要时加载图集
为了节省DrawCall一般会把相同界面或者相同类型的图片用TexturePacker打包成一张整图,比如通用的UI框体,按钮可以打包成一个图集。在每个场景创建前,加载一些必用图集,然后看情况加载其他图集。
尽量把不同的窗口做成不同的Layer或Node,每个窗口管理自己所需要的图集,避免无用图集占用内存,做到需要时加载。这点有点像Unity的组件化Component-Based思想,尽量把重复的部分(甚至不重复的部分,你永远不会想到策划哪天会突发奇想,复用某一块界面)独立,然后按需加载。
图片纹理格式
Android:推荐ETC1图片加Alpha通道的格式
IOS:推荐PVRTC4
如果效果不满足可以往上升级,考虑RGBA4444加抖动,或者直接用RGBA8888原图品质。
详细的可以参考:
利用Cache实现“只创建一次原则”
一个稍微复杂的界面里,各个标签切换可能会产生大量的重复的Button、Label或者自定义Node,利用Cache把它们存储起来进行重复利用,可以减少明显的卡顿和不必要的GC。
一个Lua的简单实现:
self.buttonCache = {
buttonTable = {},
index = 1,
getButton = function()
local index = self.buttonCache.index
local button = self.buttonCache.buttonTable[index]
if button then
button:show()
else
button = WidgetHelper.quickItemWidget()
:retain()
:setAnchorPoint(0.5,0.5)
:setTouchEnabled(true)
:onTouch(handler(self,function(self,event) end))
self.buttonCache.buttonTable[index] = button
end
self.buttonCache.index = self.buttonCache.index + 1
return button
end,
recycleButton = function()
for k,v in pairs(self.buttonCache.buttonTable) do
v:removeFromParent()
v:hide()
end
self.buttonCache.index = 1
end,
releaseButton = function()
for k,v in pairs(self.buttonCache.buttonTable) do
v:release()
end
end,
}
获取Button的时候只用调用getButton(),在切换标签或清空列表时调用recycleButton()回收Button并重新计数,在退出Scene的时候调用releaseButton()清除Cache。
不单单是Button,任何重复的组件都可以用类似的格式进行Cache存储和重复利用,可以节省一大笔创建和销毁的开销。
需要注意的是,Cache中的元素,在重复利用时要做好检查,避免出现重复添加子节点,Enable状态没有重置等问题。
提供统一的UI控件创建接口
游戏中最常见的组件,物品道具Button,TTFLabel文本,HtmlLabel文本,RichText文本,采用统一的接口创建。保持格式统一,减少重复代码。特别是物品Button,一般是一个Button底加Icon Sprite加数量Label的组合,提供一个统一接口,处理不同Item的样式,比如装备的彩色底框,碎片的角标,人物头像的星级等等,做到传入一个Item ID和Type,就能产生相应的Button。
延时加载
有时候运气比较背,一个列表里面要加载几十个子Node,每个Node上还都有动画和各种子Node,全部添加完需要2s左右,卡顿明显,除了怂恿策划美术改图之外,延时加载也是一个解决办法——不要等列表子Node加载完再显示,先显示列表,开一个计时器,每隔0.1s~0.2s添加一个子Node,在完全加载完前禁用用户交互,虽然时间差不多,但效果要明显好于让用户卡个几秒。