简介

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

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

浅谈 UIRoot、UIPanel、UICamera 组件

UIRoot组件

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

图 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 的淡入淡出以及隐藏等。

图 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 组件。

图 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 
请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!

【Unity游戏开发】浅谈 NGUI 中的 UIRoot、UIPanel、UICamera 组件的更多相关文章

  1. 【Unity游戏开发】浅谈Lua和C#中的闭包

    一.前言 目前在Unity游戏开发中,比较流行的两种语言就是Lua和C#.通常的做法是:C#做些核心的功能和接口供Lua调用,Lua主要做些UI模块和一些业务逻辑.这样既能在保持一定的游戏运行效率的同 ...

  2. C# Unity游戏开发——Excel中的数据是如何到游戏中的 (二)

    本帖是延续的:C# Unity游戏开发——Excel中的数据是如何到游戏中的 (一) 上个帖子主要是讲了如何读取Excel,本帖主要是讲述读取的Excel数据是如何序列化成二进制的,考虑到现在在手游中 ...

  3. C# Unity游戏开发——Excel中的数据是如何到游戏中的 (三)

    本帖是延续的:C# Unity游戏开发——Excel中的数据是如何到游戏中的 (二) 前几天有点事情所以没有继续更新,今天我们接着说.上个帖子中我们看到已经把Excel数据生成了.bin的文件,不过其 ...

  4. C# Unity游戏开发——Excel中的数据是如何到游戏中的 (四)2018.4.3更新

    本帖是延续的:C# Unity游戏开发--Excel中的数据是如何到游戏中的 (三) 最近项目不算太忙,终于有时间更新博客了.关于数据处理这个主题前面的(一)(二)(三)基本上算是一个完整的静态数据处 ...

  5. 【Unity游戏开发】用C#和Lua实现Unity中的事件分发机制EventDispatcher

    一.简介 最近马三换了一家大公司工作,公司制度规范了一些,因此平时的业余时间多了不少.但是人却懒了下来,最近这一个月都没怎么研究新技术,博客写得也是拖拖拉拉,周六周天就躺尸在家看帖子.看小说,要么就是 ...

  6. 喵的Unity游戏开发之路 - 推球:游戏中的物理

    很多童鞋没有系统的Unity3D游戏开发基础,也不知道从何开始学.为此我们精选了一套国外优秀的Unity3D游戏开发教程,翻译整理后放送给大家,教您从零开始一步一步掌握Unity3D游戏开发. 本文不 ...

  7. [Unity游戏开发]向量在游戏开发中的应用(二)

    本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/50972976 在上一篇博客中讲了利用向量方向的性质来解决问题.这篇博客将继 ...

  8. 关于Unity游戏开发方向找工作方面的一些个人看法

     这是个老生常谈,却又是谁绕不过去的话题,而对于每个人来说,所遇到的情况又不尽相同,别人的求职方式和路线不一定适合你,即使是背景很相似的两个人,有时候机遇也很重要. 我本人的工作经验只有一年,就业方式 ...

  9. 喵的Unity游戏开发之路 - 游泳

    原文: https://mp.weixin.qq.com/s/-ERFNB1GRZ6UAkHOhP9UQw 很多童鞋没有系统的Unity3D游戏开发基础,也不知道从何开始学.为此我们精选了一套国外优秀 ...

随机推荐

  1. java中函数是值传递还是引用传递?

    相信有些同学跟我一样,曾经对这个问题很疑惑.在网上也看了一些别人说的观点,评论不一.有说有值传递和引用传递两种,也有说只有值传递的,这里只说下个人见解 先看一个例子 public class Test ...

  2. css水平垂直居中

    margin法(水平居中) 需要满足三个条件: 元素定宽 元素为块级元素或行内元素设置display:block 元素的margin-left和margin-right都必须设置为auto 三个条件缺 ...

  3. 关于小程序swiper不显示图的那些事

    还有几天快过年了,在这里提前祝大家新年快乐! 今天没事研究了一下小程序,想整个轮播图玩玩,然后开始看看文档https://mp.weixin.qq.com/debug/wxadoc/dev/compo ...

  4. 笔记之《用python写网络爬虫》

    1 .3 背景调研 robots. txt Robots协议(也称为爬虫协议.机器人协议等)的全称是"网络爬虫排除标准"(Robots Exclusion Protocol),网站 ...

  5. Linux驱动技术(七) _内核定时器与延迟工作

    内核定时器 软件上的定时器最终要依靠硬件时钟来实现,简单的说,内核会在时钟中断发生后检测各个注册到内核的定时器是否到期,如果到期,就回调相应的注册函数,将其作为中断底半部来执行.实际上,时钟中断处理程 ...

  6. Dynamics CRM 2015-Form之控制Ribbon Button

    在上一篇中,我用一个例子,简单介绍了如何添加Ribbon Button,以及如何理解RibbonDiffXml,对这方面还不清楚的,可以先看看这篇博文:Dynamics CRM 2015-Form之添 ...

  7. [Linux] - Linux下安装jdk,tar方式

    下载jdk的linux下版本,下载页面http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.ht ...

  8. LruCache原理解析

    LruCache是一个泛型类,它内部采用LinkedHashMap,并以强引用的方式存储外界的缓存对象,提供get和put方法来完成缓存的获取和添加操作.当缓存满时,LruCache会移除较早的缓存对 ...

  9. Java中String类型的部分用法

    1.如何将字符串转换为整型数值? int i = Integer.parseInt("20"); 2.如何用“==”还是equals比较两个字符串? “==”是用来比较俩引用是不是 ...

  10. 《深入理解Java虚拟机》学习笔记之字节码执行引擎

    Java虚拟机的执行引擎不管是解释执行还是编译执行,根据概念模型都具有统一的外观:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果. 运行时栈帧结构 栈帧(Stack Frame) ...