接触Unity3D也有一段时间了,项目组在UI解决方案的选型一直是用的原生的uGUI,因此本人也是使用了一段时间的uGUI,在uGUI的使用方面积累了一些自己的经验。

   游戏中的UI与其它游戏中的元素本质上是一样的,相对来说的不同点在于,UI通常是由2D的图片组合而成,会包含较多的透明元素与渐变元素,而且一般来说会显示在屏幕的最顶层

   以前用NGUI的时候UI的深度就是一个指定的数值,数值越大越靠前,尤其在布复杂界面的时候,深度值不知道怎么填非常恶心。现在有了uGUI这问题即可迎刃而解呀~~如下图所示,B图片在A图片前面,在看看Hieraychy视图,因为A在B的上面,所以优先渲染A,然后是B。那么B就在A的上面了。。

泰课在线

那么我现在想让A图在B图的上面,那么直接在Hierarchy视图里把B拖拽放在A上面即可。

泰课在线

   如果GameObject下面有多个精灵,那么原理是一样的, 优先看父节点在Hierarchys视图中的排序,决定父节点的渲染先后。然后在依次看子节点中的Hierarchy视图的排序。如果还有孙节点一次类推。。这样的话如果没有ABA叠层的情况那么图集永远是一个drawcall.所以在布界面的时候就要花点心思这样drawcall就能节省很多了呢。

如下图所示,在深入一下渲染绘制的顺序

   UIMain 和 UINext 是同级目录,因为UINext 在UIMain下面 所以优先渲染UIMain这样UINext将在屏幕最前面。UISub原理一样,由此可得出。

精灵显示从前面的 到后面的排序   NextB > NextA >SubB>SubA>MainA>MainB 

泰课在线

布界面的时候我们可以按照这个排序来让我们的drawCall 最小化。可是如果我想运行的时候在两个图之间插一个图该怎么办?脚本如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;
using System.Collections;
 
public class UIMain : MonoBehaviour {
 
void Start ()
{
GameObject button = GameObject.Instantiate(Resources.Load<GameObject>("button"))as GameObject;
button.transform.parent = transform;
button.transform.localPosition = Vector3.zero;
button.transform.localScale = Vector3.one;
 
GameObject AObj = transform.Find("A").gameObject;
 
GameObject BObj = transform.Find("B").gameObject;
 
button.transform.SetSiblingIndex(AObj.transform.GetSiblingIndex());
 
}
 
}

transform.SetSiblingIndex 和 GetSiblingIndex就是设置与获取 GameObject在兄弟节点的位置。

   uGUI的性能其实涉及到的方面很多,这里列出来的只是目前能想到的,因为个人能力有限,可能出些纰漏。对于文中的一些建议,这里整理一下得出一些最佳实践:

  • 设计UI时要考虑重用性,如一些边框、按钮等,这些作为共享资源,放在1~3张大图集中,称为重用图集
  • 其它非重用UI按照功能模块进行划分,每个模块使用1~2张图集,为功能图集
  • 对于一些UI,如果同时用到功能图集重用图集,但是其功能图集剩下的“空位”较多,则可以考虑将用到的重用图集中的元素单独拎出来,合入功能图集中,从而做到让UI只依赖于功能图集。也就是通过一定的冗余,来达到性能的提升。
  • 有相同材质和纹理的UI元素是可以Batch的,可以Batch的UI上下叠在一块不会影响性能,但是如果不能Batch的UI元素叠在一块,就会增加Drawcall开销。
  • 要注意UI元素间的层叠关系,建议用“T”工具查看其矩形大小,因为有些图片透明,但是却叠在其它UI上面了,然后又无法Batch的话,就会无故多许多Drawcall;
  • UI中出现最多的就是Image与Text组件,当Text叠在Image上面(如Button),然后Text上又叠了一个图片时,就会至少多2个Drawcall,可以考虑将字体直接印在下面的图片上;
  • 有些情况可以考虑人为增加层级从而减少Drawcall,比如一个Text的层级为0,另一个可Batch的Text叠在一个图片A上,层级为1,那此时2个Text因为层级不同会安排2个Drawcall,但如果在第一个Text下放一个透明的图片(与图片A可Batch),那两个Text的层级就一致了,Drawcall就可以减少一个。
  • 应该尽量避免使用Mask,其实Mask的功能有些时候可以变通实现,比如设计一个边框,让这个边框叠在最上面,底下的UI移动时,就会被这个边框遮住;
  • 如果要使用Mask时,需要评估下Mask会带来的性能损耗,并尽量将其降到最低。比如Mask内的UI是动态生成的话(像List组件),那么需要注意生成的UI之间是否有重叠的现象;
  • 有空多来“泰斗社区”看看就行了。