【Unity游戏开发】浅谈 NGUI 中的 UIRoot、UIPanel、UICamera 组件

时间:2021-05-18 22:52:34

简介

马三最近换到了一家新的公司撸码,新的公司 UI 部分采用的是 NGUI 插件,而之前的公司用的一直是 Unity 自带的 UGUI,因此马三利用业余时间学习了一下 NGUI 插件的使用,并把知识点记录成博客与大家分享。

在我们使用 NGUI 插件创建的 UI 中,可以发现 UIRoot 物体和 Camera 物体上面都带有 NGUI 特有的脚本组件,其中 UIRoot 物体上面带有 UIRoot 和 UIPanel 两个组件,而子物体 Camera 带有一个 UICamera 组件,这三个都是 NGUI 体系中比较核心的组件,今天我们就来仔细研究一下他们。

浅谈 UIRoot、UIPanel、UICamera 组件

UIRoot组件

UIRoot 组件总是出现在 NGUI 的 UI "树"的最顶层,也就是那个“根”物体中。如下图:

【Unity游戏开发】浅谈 NGUI 中的 UIRoot、UIPanel、UICamera 组件

图 1:UIRoot UIPanel 展示图

它的作用是缩放 UI。美术人员制作的图片一般都是以像素为单位,比如 1280 x 720 等等,而 Unity 中则是以米为单位,如果一个 100 x 100 的像素 UI 元件放入到一块 1000 x 1000 分辨率的屏幕中,按理说这个 UI 元件应该是屏幕大小的 1%,但是因为 Unity 中的单位是米,所以它会从 100 x 100 像素的大小变为 100 x 100 米,这样就会导致一个小 UI 变得非常非常大,而 UIRoot 这时就会通过屏幕来缩放 UI 控件,让 UI 控件在视觉上是正常的。

在 UIRoot组件中,它提供了 3 中缩放的方式(即 UIRoot 组件下的 Type 值),分别为:PixelPerfect、FixedSize、FixedSizeOnMobiles。

PixelPerfect 指的是永远保持像素大小不变,比如一张 100 x 100 像素的图片,在 500 x 500 分辨率的屏幕上,它是 100 x100 像素,在 1000 x 1000 像素的屏幕上,它依旧是 100 x 100 像素,因为它的源文件就是这个大小,而 PixelPerfect 让它一直保持这个大小。这样就可以让 UI 的图片永远保持最清晰,但是这个模式的缺点是会导致在高分辨率下 UI 显得特别小,而低分辨率下 UI 又会显得特别大。

FixedSize 模式和上面的模式正好完全相反。在 FixedSize 模式中,NGUI 将不再保护图片的原始尺寸,只会关心 NGUI 自己所需的缩放参数,这种模式下必须设置 UIRoot 的 ManualHeight 值,然后 NGUI 会将所有的控件按照和这个值的比例进行缩放。比如:设置 ManualHeight 的值为 1000,然后一张 100 x 100 像素的图片在高度为 1000 的屏幕分辨率下的占 1/10 的高度,那么当 UI 放到一个分辨率为 500 x500 的屏幕上时,它依然占 1/10 的高度,只不过图片的尺寸被自动缩放为 50 x 50。这样就保证了 UI 和屏幕的分辨率比例是一定的。

FixedSizeOnMobiles 是两种方案的结合体,它会让 UI 在 Pc、Mac、Linux 系统下自动采用 PixelPerfect,而在移动设备上自动采用 FixedSize。

如果没有选择 FixedSize,那么必须设置另外两种缩放模式下的 MinimumHeight 和 MaximumHeight 两个值。比如:选择 PixelPerfect 模式,将 MinimumHeight 设置为 720,将 MaximumHeight 设置为 900,那么在一个分辨率为800 x 600 的屏幕上,因为屏幕分辨率的高度小于 UIRoot 中的最小高度, UIRoot 就会按照 FixedSize 模式下 ManualHeight 为 720 的情况进行处理。同理,如果将 UI 放到一个分辨率为 1920 x 1080 的屏幕上,因为该屏幕的分辨率高度 1080 大于设置的 900,于是 UIRoot 就会按照 FixedSize 模式下 ManualHeight 为 900 的情况进行处理。(在 NGUI3.7.0 以后缩放模式变为了 Flexible:等同于 PixelPerfect、Constrained:等同于 FixedSize、ConstarinedOnMobiles:等同于 FixedSizeOnMobiles)。

UIPanel组件

如下图所示,UIPanel 也有很多的属性。其中,Alpha 属性顾名思义是透明度,默认为 1 不透明。它将控制它下面所有 Widget 的透明度。(所有的 UI 控件都带有 Widget,因为它们都继承自 Widget)也就是说,它会让它的子物体里的所有的 UI 控件都一起发生透明度变化,可以用来做整个 UI 的淡入淡出以及隐藏等。

【Unity游戏开发】浅谈 NGUI 中的 UIRoot、UIPanel、UICamera 组件

图 2:UIPanel 展示图

Depth 深度属性是一个非常重要的属性。在 NGUI 中,每一个 Panel 都有 Depth,每一个 Widget 控件也都有 Depth,Depth 将决定渲染的顺序,直接影响了 UI 之间的的前后重叠关系。Depth 越高的控件将会显示在视野的上层,Depth 越高的 Panel 也会显示在视野的上层。但是 Panel 的 Depth 权重要远远高于 Widget,也就是说,在大部分的情况下,属于低 Depth 的Panel 的控件,无论你怎么去提高控件的 Depth,它都将显示在高 Depth 的 Panel 的控件后面。当你有多个 Panel 的时候,比如你制作了多个面板界面,每个界面都有一个 Panel ,那么此时尽量保证这些 Panel 不要共用同一个 Depth,因为这将会导致 NGUI 在渲染的时候无法以 1 个 DrawCall 完成,会以增加 DrawCall 的方式来保证渲染顺序不混乱,这样就增大了性能的开销。不过 NGUI 在碰到 Panel 有共用的 Depth 时,会做出提醒。

Clipping 是剪辑窗口的意思,它可以让一个面板只显示某一块区域,这个功能在 ScrollView 滚动框或者滚动列表中非常有用。Clipping 一共提供了 3 中模式:

  • None:无剪辑模式,在这种模式下,滚动视框中的物体可以被拖动,但是视窗因为没有剪辑,所以是没有边界的。这将可能导致内容被拖出屏幕外再也拖不回来。就像我们往下拖动浏览网页时会拖到一个所谓的“底”,None 模式就是没有这个“底”,你可以将内容全部拖出屏幕以外。
  • SoftClip:柔和剪辑模式,我们一般都会使用这种模式来制作 ScrollView。在这种模式下,Panel 将会剪辑出一块可视区域出来显示,这个被剪辑出来的区域以外的部分将会被剪辑掉而无法显示出来。
  • Constrain but don't Clip:这种模式是指视窗会尽量地包含所有的内容,但是不剪辑它们,效果大约等同于有边界但是边界为全屏,无法完全将内容拖到屏幕外面去,只要在屏幕范围内,都能看到内容,内容并不会被剪辑掉。

Render Q 可以理解为渲染顺序,默认为自动设置。这个选项在和粒子系统结合使用的时候会有影响(下文会单独拿出一段来解释它)。如果该 Panel 下的 UI 需要被灯光影响到(NGUI 的 UI 默认是不会接受灯光照射效果的),则需要勾选 Normals。如果该 Panel 下面所有的 UI 控件都不会被移动,那么可以勾选 Static 来将他们设置为静态的,这样该 Panel 下所有的控件将会忽略位置、旋转、缩放等操作,永远保持不动。虽然这样可以提高一些性能,但是慎重使用。

这段我们来主要了解一下 Render Queue 和粒子系统的一些联系。有的时候,我们会发现粒子不能正确的显示在界面上面,很多情况就是 Render Queue 的锅。在上面我们了解到了,在 NGUI 中,渲染的层级关系是由 Depth 决定的,但是最本质的还是由渲染的 Render Queue 决定的,这是一个 Shader 中常见的参数。在 NGUI 中,每一个 Panel 上也有一个 RenderQ 的设置项,RenderQ 越高的将会越在上层显示。粒子系统的 RenderQ 一般是 3000,所以,如果我们希望粒子处于两个 Panel 之间,只需要将其中一个 Panel 的 RenderQ 改为 StartAt 模式,将值设为 3000 以下的值,然后将另外一个 Panel 的 RenderQ 设为 3000 以上的值,就可以让粒子在两个 Panel 之间显示了。当然,如果只需要让粒子显示在最上层,最简单的办法就是加入一个摄像机,给这个粒子设置一个单独的 Layer ,让新加入的摄像机只渲染粒子所在的 Layer,将这个摄像机的 Clear Flag 设为 Depth Only,然后把渲染的 Depth 值设为最高的即可。

点击 Show Draw Calls 按钮,可以看到该 Panel 下的所有的 DrawCall 消耗情况。

UICamera 组件

下图即为 UICamera 组件的截图,UICamera 这个组件的核心作用是:让带有这个组件的摄像机渲染出来的物体能够接受 NGUI 事件。如果我们自己创建了一个物体,并且希望对这个物体使用一些 NGUI 中的事件,比如 OnPress()、OnDrag() 等,就需要为渲染这个物体的摄像机添加 UICamera 组件。

【Unity游戏开发】浅谈 NGUI 中的 UIRoot、UIPanel、UICamera 组件

图 3:UICamera 展示图

在 UICamera 中,大部分的设置我们都不用去改变,它让我们的事件支持多点触摸、鼠标键盘触摸屏等事件的接受。但是要注意的是 EventMask 这个选项,这个 EventMask 和相机中的 CullingMask 非常相似,相机的 CullingMask 是为了选择渲染哪些层的物体,而 EventMask 是为了选择接受哪些层的物体的事件。UICamera 会默认只接收我们创建 UI 时被自动设置的那个 Layer,但是,如果我们在制作 UI 过程中,在创建 UI 后因为某些原因修改了 UI 的层,一定要记得将 UICamera 的 EventMask 修改过来,否则将会发现,我们单击 UI 没有反应,因为它接收不到这个 Layer 的物体的事件。

作者:马三小伙儿
出处:http://www.cnblogs.com/msxh/p/6574554.html 
请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!