4.2.2 UGUI系统的组件
接下来介绍UGUI系统的核心组件,包括它们的用途、运行机制和原理。
1. Canvas组件
Canvas组件,我们暂且叫它画布。Canvas相当于画画时铺在上边的画板,我们把各类元素放在画布上后,Canvas要做的事情就是合并这些元素。
合并的规则为,在同一个Canvas里,将相同层级、相同材质球的元素进行合并,从而减少drawcall。但相同层级并不是指gameobject上的节点层级,而是覆盖层级。Canvas里如果两个元素重叠,则可以认为它们是上下层关系,将所有重叠的层级数排列顺序计算完毕后,将从第0层开始的同一层级的元素合并,再将第1、2、3……层的元素同样合并,以此类推其他层。
Canvas上的参数Render Mode(渲染模式)比较重要,这里详细介绍一下。你可以选择不以Camera为基准的Overlay模式,也可以选择以Camera为基准的Screen Camera模式,还可以选择以3D世界为基准的World Space模式。三者适用于三种不同的使用场景。
Overlay模式并不与空间上的排序有任何关系,空间上的前后位置不再对元素起作用,它常用在纯UI系统的区域内,这种模式下,Camera排序有别于其他模式,Sort order参数在排序时被重点用到,Sort order参数的值越大,越靠前渲染。
Screen Camera模式相对通用一点,它依赖于Camera的平面透视,渲染时的布局依赖于它绑定的Camera。想让更多的非UGUI元素加入UI系统中,Screen Camera模式更有优势。这种模式是实际项目中制作UI系统最常用的模式,不过UGUI系统底层针对排序有一些规定,如对元素的z轴不为0的元素,会单独提取出来渲染,不参与合并。
World Space模式主要用于当UI物体放在3D世界中时,比如,一个大的场景需要将一张标志图放在一块石头上,这时就需要World Space模式。与Screen Camera的区别是,它常在世界空间中与普通3D物体一同展示,依赖于截锥体透视(Perspective)Camera。它的原理挺简单,与普通物体一样,当UI物体在这个Camera视野中时,就相当于渲染了一个普通的3D图片,只是除了普通的渲染Canvas外,还会对这些场景里的UI进行合并处理。
2. Canvas Scaler组件
这是一个屏幕适配组件,用来指定画布中元素的比例大小。有简单指定比例大小的Constant Pixel Size模式,也有Scale With Screen Size模式,它具有以屏幕为基准的自动适配比例大小的规则,或者Constant Physical Size模式,它具有以物理大小为基准的适配规则。在实际手游项目里,设备的屏幕分辨率变化比较大,通常使用以屏幕为基准的自动适配比例大小的Scale With Screen Size选项。
3. Graphic Raycaster组件
它是输入系统的图形碰撞测试组件,它并不会检测Canvas以外的内容,检测的都是Canvas下的元素。当图元素上存在有效碰撞体时,Graphic Raycaster组件会统一使用射线碰撞测试来检测碰撞的元素。也可以设置完全忽略输入的方式来彻底取消点击响应,还可以指定阻止对某些layers进行响应。
4. EventTrigger组件
它是输入事件触发器,与此脚本绑定的UI物体都可以接收输入事件。比如(鼠标、手指)按下、弹起、点击、开始拖曳、拖曳中、结束拖曳、鼠标滚动事件等。它主要起到点击响应作用,配合前面的Graphic Raycaster进行响应。
5. Image组件、RawImage组件
这两个组件是UI系统里的主要部件,它们可以对图片进行展示,包括图片、图集。
两者的区别是,Image组件仅能展示图集中的图元,但展示的图元可以参与合并,而RawImage组件能展示单张图片,但无法参与合并。通常我们会将小块的图片打包成图集来展示,这样性能更高,也更节省内存,这也是UGUI系统自动集成的功能,每个图片资源都有一个tag标记,标记决定了哪些元素会合并到同一张图集内,如果没有tag标记,则默认不会合并图集,它自己就是自己的图集。
不使用图集而使用RawImage展示单张图片时,通常都是图片尺寸太大而导致合并图集的效率太低,或者相同类型的图片数量太多,导致合并图集后的图集太大,而实际在画面上需要展示的这种类型的图片又很少,图集方式反而浪费大量内存空间,因此使用RawImage逐一展示即可。
6. Mask组件、RectMask2D组件
它们是遮挡组件,可以将其子节点下矩形区域外的内容剔除,是滚动窗口中最常用的组件。
这两个组件主要是在剔除的方法上有所区别,虽然实现效果上都一样,但其中Mask组件使用顶点重构的方式剔除矩形区域外的部分,而RectMask2D组件则采用着色器的剔除方式,每个元素都有自己的材质球实例和实例参数。
Mask组件和RectMask2D组件具体的剔除算法和源码分析将在后面讲解。
7.其他组件
其他逻辑组件都是可以重写的,如按钮组件Button、切换组件Toggle、滚动条组件ScrollBar、滑动组件Slider、下拉框组件DropDown、视图组件ScrollView。如果不想使用它们,觉得它们的功能不够用,也可以用Image、Mask等几个核心组件组合后重写。
实际工作中,很多项目都会自定义属于自己的组件。为什么要自定义呢?很多时候,项目里的需求是多样化的,若有自己的组件,在有特殊需求和特殊逻辑时,就能够毫不费劲地更改。所以,大部分项目中都会重写一些组件来给自己的项目使用,也有一些人总结了这些组件的经验,编写了比较好用的组件开源放在Github上。