Canvas 组件是 UI 的基础画布,所有的 UI 组件都在 Canvas 组件下面,并且支持嵌套,Canvas 有三种绘制方式,可在 Render Mode 中选择

  • Screen Space Overlay,这个会把 UI 绘制在所有的游戏物体前面,注意需要将 Overlay 的 Canvas 放到 hierarchy 面板的最上面,避免不能完成自己想要的效果。
  • Screen Space Camera,最常用,可以把正交摄像机投影出来的 UI 元素绘制在 Canvas 面板上。
  • World Space,将整个 Canvas 当成一个 3D 物体放在场景中。

如何区分前两中方式,其实可以放一张全黑的 image,然后加一个 Cube,如果是 Overlay 的渲染方式,那么不管 Cube 摆放在场景中的什么位置,都是看不到它的,如果是 Camera 的方式,用主相机的视角,那么将 Cube 放在 UI 的前面,就可以看到 Cube 了。

自适应屏幕

Canvas Scaler

Canvas 下还有一个 Canvas Scaler 组件,一般将 UI Scale Mode 设置为 Scale With Screen Size,确定了分辨率之后让 UI 美术人员按照这个屏幕尺寸来画图片和布局,Screen Match Mode 最好设置为 Expand,如果是 Match Width Or Height,可能会出现画面显示不全的问题。

相机

游戏场景中一般有一个 3D 摄像机(主相机),还有一个 UI 摄像机(目前不知道 UI 摄像机用在哪里,猜测应该是新建一个摄像机,然后将 Render Mode 调整为 Screen Space Camera),最好是先渲染主相机,再渲染 UI 摄像机,这样 UI 就会出现在场景前面了,一般主相机的 Depth 值为 -1,我们只需要将 UI 摄像机调整为 >0 即可。UI 摄像机还需要设置为是正交模式,Cilpping Planes 的最小值建议设置为 0,不然有时候有些 UI 会被剔除掉。

锚点对齐方式

一直在用,不多说了。

背景图全屏

背景图一般有两种方式,一种是允许图片变形,可以在 Rect Transform 设置允许横向纵向都支持拉伸,这样图片会一直跟屏幕大小保持一致,但是会产生形变;另一种是不允许形变,但当屏幕大小发生改变的时候,会产生适当的裁剪,实现方式是给 image 添加 Aspect Ratio Fitter 组件,并且在 Aspect Mode 中选择 Envelope Parent。

布局组件

GUI 有一组 Layout 组件,Horizontal Layout Group(横向布局),Vertical Layout Group(纵向布局),Grid Layout Group(表格布局)。
将层次结构设置为:

  • LayoutTest (Empty Game Object)
    • Image (Image)
    • Text (Text)
    • Image(1) (Image)

然后在 LayoutTest 上绑定 Horizontal Layout Group,三个子元素会自动调整为横向布局,此时仍然可以改变 LayoutTest 的大小,但是加上 Content Size Fitter,并且将 Horizontal Fit 和 Vertical Fit 都设置为 Preferred Size 之后,就无法改变 LayoutTest 的 Rect Transform 了。同理,将 Text 绑上 Content Size Fitter,并将 Horizontal Fit 设置为 Preferred Size,再将 Vertical Fit 设置为 Unconstrained,也就是 “锁定” 了 Text 的 Width,这样可以达到以下的效果,也就是直接修改 Text 的字号,依然可以保持下面的布局。

Content Size Fitter 组件可以重新计算子对象的 RectTransform 区域,所以如果子对象很多的话,效率就不是很高。也有可能是出于效率的考虑,Content Size Fitter 需要等一帧才能计算出正确的区域。如果想要立即取到正确的区域,那么可以使用:

1
LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform);

Canvas 优化

UGUI 会自动合并批次,原理是它会把一个 Canvas 下的所有元素合并在一个 Mesh 里。如果 Canvas 下的元素很多,任意一个元素发生位置、大小的改变,就需要重新合并所有元素的 Mesh。如果元素很多的话,就会发生卡顿。
比较好的做法是每个 UI 界面都设置成一个 Canvas,如果界面下元素较多的话,可以多嵌套几个 Canvas,尤其是会频繁改变位置的元素,这样可以降低合并 Mesh 的开销,但是 Canvas 套的太多的话,也会导致 DrawCall 上升,因为每个 Canvas 都会单独占用一个 DrawCall。

参考

CSDN:UGUI之Content Size Fitter组件