北京
图书在版编目(CIP)数据
Unity 3D NGUI实战教程/高雪峰编著.--北京:人民邮电出版社,2015.3
ISBN 978-7-115-38546-8
Ⅰ.①U… Ⅱ.①高… Ⅲ.①游戏程序—程序设计—教材 Ⅳ.①TP311.5
中国版本图书馆CIP数据核字(2015)第036349号
内容提要
NGUI 是专门针对 Unity 引擎、用 C#语言编写的一套插件,它已经成为了目前世界上应用最广、最成熟的Unity制作UI的插件,完美地弥补了Unity引擎原生GUI系统和NewGUI系统的各种不足。程序员可以利用它提供的一整套UI框架和事件通知系统来进行自己项目的UI设计和制作。本书不仅讲解了必知必会的 NGUI 的基础知识,更是以项目实战为目的,涵盖了大量的项目实战中的经验之谈和技巧总结,用以帮助读者达到学以致用的目的。
本书的主要内容:初识NGUI、UI开发的流程、NGUI强大优势、制作第一个UI图集、创建一个3D UI、查看和管理UI的深度、制作基础的UI控件、让UI动起来——UI动画、NGUI进阶、使用Panel管理面板、NGUI 实战进阶、UI 开发核心问题——UI随屏幕自适应、实战开发中 UI资源制作标准、跨平台制作UI资源、UI结构设计、UI代码的设计和优化、项目案例实战分析、背包界面的制作等核心技术,最后用一章归纳了NGUI常见疑难问题,以便读者遇到问题时可以随时参考。
本书适合新上手的Unity客户端程序员、需要做UI的Unity程序员、想自学Unity做独立游戏开发的人员,以及大专院校相关专业的师生学习用书和培训学校的教材。
◆编著 高雪峰
责任编辑 张涛
责任印制 张佳莹 焦志炜
◆人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
网址 http://www.ptpress.com.cn
北京天宇星印刷厂印刷
◆开本:800×1000 1/16
印张:15
字数:358千字 2015年3月第1版
印数:1-3000册 2015年3月北京第1次印刷
定价:49.00元
读者服务热线:(010)81055410 印装质量热线:(010)81055316
反盗版热线:(010)81055315
在手机游戏开发兴起的当下,Unity 3D 引擎依靠其良好的跨平台特性,一跃成为全球第一大引擎,被广泛地使用。越来越多的游戏开发者开始关注和使用Unity 3D 引擎。Unity 3D引擎最大的短板在于其原生的GUI系统有很大的缺陷,例如,性能和方便程度等都不适合进行商业开发,所以,大部分开发者都开始使用NGUI。NGUI的GUI以良好的性能优化、方便的开发模式、成熟稳定等特点,已经成为全球 Unity 游戏开发者的 UI 制作首选插件。因为NGUI是一个插件的缘故,网上很难有成熟的资料,即便要查找一些基本的资料也得连入国外的网站,而且是英文的资料,这给开发者带来了很大的苦恼。由于 UI 开发是游戏开发中客户端的重头工作,具有责任大、工作量多、修改频繁等诸多特性,一直是客户端程序员的一个疑难问题。现在市面上还没有NGUI的书,为了让读者能够学会NGUI的用法和技巧,并且能够直接运用于正式的商业项目开发中,作者结合自己的实践经验特意撰写了本书。
本书的特点
本书不仅讲解了必知必会的基础知识,更是以项目实战为目的,书中涵盖了大量的项目实战中的经验之谈和技巧总结,这对于一个客户端程序员来说,不管他用什么引擎、用什么 UI工具来开发UI系统,本书都能给他提供帮助,达到学以致用的目的。
本书的主要内容
本书全面讲解了NGUI的实战知识,主要内容为:初识NGUI、UI开发的流程、NGUI强大优势、导入NGUI插件、认识UI的基本资源、制作第一个UI图集、用AtlasMaker制作图集、制作第一个UI字体、创建一个3D UI、3D UI的工作原理、查看和管理UI的深度、制作基础的 UI控件、精灵的创建、制作UI纹理、制作按钮、制作进度条、制作滑动条、制作输入框、制作滚动视图、制作复选框、让UI动起来——UI动画、颜色变化动画、位置变化动画、旋转变化动画、大小变化动画、组件整体变换、音量变化动画、在UI中使用Animation动画、动画控制——UIPlayTween组件、NGUI进阶、使用Panel管理面板、使用Grid排列元素、使用Toggle制作页签、使用DragCamera直接拖动摄像机、使用DragObject直接拖动物体、拖动改变UI元素的尺寸、按钮绑定快捷键、制作列表、打字机慢慢出字的效果、NGUI实战进阶、UI开发核心问题——UI随屏幕自适应、背景图的适配、UI元素的相对自适应、多个摄像机同时协作运行、实战开发中UI资源制作标准、跨平台制作UI资源、巧用九宫格减少UI资源量、UI事件监听的遮挡、NGUI和模型、特效在同一层中混用、UI结构设计、用代码操作NGUI的类、获取NGUI的组件、迅速判断类中可读写的成员、动态创建UI元素、Sprite的常用操作、动态对 Button 设置单击事件、网格动态增减成员和刷新排列、手动控制动画随意播放、调用进度条、巧用 EventTrigger 监听各种事件、UI 代码的设计和优化、项目案例实战分析、场景加载的进度条界面制作、RPG 游戏中人物头像状态栏的制作、技能快捷栏的制作、RPG角色头顶跟随血条的制作、背包界面的制作等核心技术,最后用一章归纳了NGUI常见疑难问题,以便读者遇到问题时可以随时参考。
本书作者
高雪峰,现为游戏制作人,曾经担任游戏主策划、游戏运营、Unity程序员等职位,开发过端游、页游、手游等项目,带团队做过多个商业项目,对游戏的研发过程具有丰富的经验和实战技能。对NGUI有深入的研究,并且全部应用于项目实战,本书是作者多年实战经验的总结,定会给读者带来很多有益的实战启示。
本书读者对象
本书适合新上手的Unity客户端程序员、需要做UI的Unity程序员、想自学Unity做独立游戏开发的人员阅读,也适合用作大专院校相关专业的师生学习用书和培训学校的教材。
编辑联系邮箱:zhangtao@ptpress.com.cn。
UI全称是User Interface,即用户界面。UI的概念运用于各行各业,例如电脑操作系统、手机、网站等,几乎所有需要用户自主操作的地方都会涉及用户界面。UI的职责是负责人机之间的交互,它需要将关键信息、操作逻辑等展示给用户。好的UI设计不但能使操作变得易于理解、简单易用,而且能做到简洁美观,给用户带来舒适的操作体验。在软件设计中,UI的设计是核心设计工作之一。
游戏是一种非常典型的互动娱乐,不论在什么游戏中,玩家都需要进行自己的操作,而且频率非常高。在一些大型游戏中甚至会出现更复杂而频繁的操作,例如竞技游戏和大型网络游戏等。这些在游戏中进行的操作,让玩家体会到了游戏的乐趣,而这一切都依赖于一整套游戏的UI机制。
在游戏中,UI 几乎无处不在,例如进入游戏的菜单、输入账号密码的登录界面、创建和选择角色、角色血条状态栏和技能栏、场景雷达图、各种各样的提示框等。
在游戏中UI主要承担了以下职责:
1.游戏美术风格的重要组成部分
一个游戏由不同种类的美术资源组成,例如角色、场景、特效、UI 等。每一个游戏都必须有一个统一的美术风格,否则游戏将变成不伦不类的四不像。例如中国仙侠风格的游戏,不应该出现欧美魔幻的元素;同理,欧美魔幻风的游戏里,不应该出现中国仙侠的元素。UI 因其无处不在的特性,成为游戏设定美术风格时一个非常重要的考量指标。
2.承担着重要的美观职责
当玩家打开游戏看到第一个游戏画面时,UI 就将一直陪伴着玩家直到玩家退出游戏。甚至大部分UI都是长久性地出现在玩家的游戏窗口中,例如玩家角色的状态栏、技能栏等。所以,UI的美观和耐看,将会直接影响着玩家对这款游戏的美观程度的评价。
3.负责清晰明了地展现游戏的操作方式
每一个游戏都有着自己的操作方式,越是大型游戏,操作逻辑往往会越复杂和庞大。好的UI设计,能让用户不依赖指引就能够迅速地知道自己应该怎样操作来进行游戏。
4.能让玩家舒服、方便地进行人机交互
游戏UI的核心目的就是让玩家能进行自主操作,而游戏的机制往往很复杂,这个时候“人性化”就变得很重要。例如技能冷却完成之后,技能栏闪烁一下,玩家在游戏中不自觉地就能知道技能已经冷却完成。
在项目开发中,一般都是由策划人员、程序人员、美术人员、测试人员组成多个组协同进行开发。在开发 UI时,首先应当由美术核心人员确立 UI的整体美术风格标准,然后再进行UI的各个模块的开发。
在开发 UI的模块时,首先应当由相关策划人员提出功能的需求,指出该模块的UI应该具备什么功能、能让玩家进行哪些操作逻辑。然后,由策划人员给出UI的控件布局图或者由美术人员自行设计布局图。再由UI美术人员进行UI的资源制作,制作完成后,将UI资源提交给客户端程序员。客户端程序员拿着美术人员提供的UI资源,按照 UI的布局图和功能文档,最终完成该模块的功能开发。
UI在开发中往往具备以下几个问题。
(1)需求不清晰。
(2)功能难实现。
(3)工作量很大。
(4)优化不够好。
(5)改动太频繁。
这些问题都是项目实际开发中非常常见的问题,特别是客户端程序员经常为以上五个问题伤脑筋。要规避它们,除了良好的沟通以外,还需要足够的对UI的思考,以完成一个良好的UI架构来提高抗风险指数,并扩充自身的知识面,以做到提早考虑到更多的特殊情况。
看完本书后,相信你一定能找到应对以上项目开发实际问题的最优方案!
NGUI是专门针对Unity引擎、用C#语言编写的一套插件,经历了数十个版本的更迭之后,它已经成为了目前世界上应用最广、最成熟的Unity制作UI的插件,完美地弥补了Unity引擎原生GUI系统和NewGUI系统的各种不足之处。程序员可以利用它提供的一整套UI框架和事件通知系统来进行项目的UI设计和制作,NGUI凭借其强大的功能、良好的优化和易用易学性,让大多数程序员都赞赏有加!
1.成熟稳定
NGUI 经历了数十个版本的更迭,发展到现在几乎没有 BUG,并且完美支持跨平台和自适应。在这一点上,它远远超越了其他的UI插件。论成熟稳定,它比Unity的NewGUI还要更胜一筹。
2.功能丰富
NGUI除了满足普遍的UI制作功能以外,还集成了大量的封装好的实用功能,比如拖曳、更多的事件监听、各种Tween动画、本地化等,甚至支持光照、法线、折射等特性。这是NGUI远远超过其他UI制作方式的地方,也是NGUI经历数十个版本更迭的积累。
3.操作方便
NGUI的操作几乎都集中于Inspector面板中,并且不需要Play运行就能看到UI的结果。各个模块和组件封装非常好,需要功能时只要为其附上相应的NGUI组件就可以完成,大部分功能都不需要自己写代码。
4.极致优化
目前最新的 NGUI 版本中,对于 UI 的渲染性能已经优化到了极致,使用 1 个 DrawCall就能完成绝大部分UI的渲染。
5.高灵活性
NGUI都是以组件形式使用,程序员可以不借助任何外部的资源进行UI的制作,可以让任何一个控件通过改变其组件的方式,自由地变换为按钮、精灵、进度条、输入框等。
NGUI插件目前较新的版本是3.6以后的版本。
在NGUI 3.0 以前的时期,底层的事件通信体系完全依赖于SendMessage,这是一个效率比较低下的发消息方式,那个时期大多数Unity的开发者都在使用当时很流行的NGUI 2.6 版本,甚至目前还有少数开发者在使用。
在NGUI 3.0 及以后的版本中,NGUI 进行了大革新,其中革命性的就是将整个的底层消息机制全部换为效率高的EventDelegate。并且开始重视NGUI的性能优化,一直到3.6时期, NGUI相比以前,提高了事件分发的效率,将性能优化到了极致,整合了大量的相近功能,并大大丰富了NGUI的功能类型。
在本书中,将使用比较新的NGUI 3.6.8版本进行讲解,书中可能部分截图并不是3.6.8的版本,但是NGUI 3.6.0 及以后的版本几乎都一样,本书的知识点通用于NGUI 3.6.0 及以后的所有版本,读者大可放心。
NGUI本身是一个付费插件,开发者可以从Unity官方的AssetStore(官方提供的Unity资源买卖平台,里面有很多第三方的资源和插件出售,有的收费有的免费)中去购买,售价大约95美金(折合人民币591元)。用户可以从Unity引擎的编辑器界面的顶部Window菜单中选择Asset Store进入,如图2.1所示。也可以在浏览器中输入网址https://www.assetstore.unity3d.com/进入。
因为NGUI正版插件价格不菲,如果仅仅是为了学习和练习,开发者可以从网上去下载他人购买的NGUI插件包来使用,效果是一样的。不管是从官方购买的还是自己从第三方网站上下载的NGUI插件,它都应该是一个格式为“.unitypackage”的Unity资源包文件,如图2.2所示。
当下载好NGUI的插件资源包之后,下面要做的就是将NGUI资源包导入到引擎中进行使用。
如图2.3 所示,在Unity编辑器顶部菜单栏中的Assets 菜单中选中Import Package,然后选择 Custom Package(自定义资源包),弹出图 2.4 所示的资源路径窗口,在其中找到 NGUI资源包所在的位置,单击“打开”按钮即可。
特别注意:请将NGUI资源包放在一个没有中文的路径下再进行导入(例如F:\DownLoad\NGUI-Next-Gen-UI-v3.6.8)。因为 Unity 导入外部资源时,将无法导入带有中文路径的资源,例如F:\下载\NGUI-Next-Gen-UI-v3.6.8因为将NGUI放在了中文名文件夹“下载”之下,将导致NGUI资源包无法成功导入。
单击“打开”按钮后,等待Unity引擎解压资源包,然后将会在Unity引擎界面中弹出图2.5所示的窗口,展示该资源包的内容列表,让用户选择导入哪些资源(默认情况下是全部选择),此时因为其已经默认全部选择,可以直接单击Import按钮,将其全部导入。
导入成功后,可以看到NGUI文件在Project视图中的结构图(如图2.6所示),其中Editor文件夹是编辑器所用的,不用管它;Examples文件夹是 Unity制作的一些基本案例,读者可以从Examples下面的Scenes文件夹中选择它制作的范例场景来参看一些基础功能的制作,如图2.7所示。Resources文件夹存储着NGUI自带范例所用到的资源。最后就是整个NGUI对于开发者来说最核心的文件夹:Scripts,这里面是NGUI已经封装好的各个功能模块的脚本,当需要使用时只要把相应的脚本变成UI物体的组件就可以进行相关的操作了,本书在后文将会介绍更简单的使用方式。
另外,导入之后还会注意到Unity编辑器顶部菜单栏中多了一项NGUI菜单,如图2.8所示,这个菜单将会是以后使用NGUI制作UI系统最常用的一个菜单。
好了,到这里就已经说明你已经成功地导入了NGUI插件,这个插件包大约12MB,不过完全不用担心它会让你的项目安装包增大很多,因为NGUI插件包导入后并不存在于Resources文件夹下面,所以在项目工程最后发布时,它只会将NGUI资源包中你所用到的部分纳入打包资源,对项目发布的游戏安装包体积的影响几乎可以忽略不计。
(1)如果我的工程文件中已经导入过一次NGUI的资源包了,此时我再导入一个新的NGUI资源包会有什么结果?
答:会根据路径替换掉同名文件,并导入额外的新文件。
(2)导入解压后,并没有弹出图2.5所示的资源包内容预览窗口,而是在Unity编辑器窗口底部报出了一行如图2.9所示的错误,怎么办?
答:这是因为你将NGUI资源包放在了一个带有中文名称的文件夹路径下,Unity导入任何带有中文路径的资源包时,都会弹出这个错误导致无法导入。请将你要导入的资源包放在一个没有任何中文的路径下再进行导入。
(3)我怎样查看我的NGUI版本是多少?
答:在Project窗口中,选择Assets文件夹下面的NGUI文件夹,然后会看到一个ReadMe的版本说明文件,这个文件名会带有版本号,如图2.10所示。
我们在制作 UI时,经常将一些零碎的小的 UI资源(比如,一个小箭头、一个按钮等)打包成一张大图,然后在使用时,只使用这个大图中的一部分(例如,只使用其中小箭头的那一小块),那么这一块“被切出来”的图片,就可以称之为精灵。
如图2.11所示的就是一个又一个的UISprite。
我们在制作 UI时,会将一些零碎的小的UI资源打包到一张大图中,然后再通过精灵的方式对这张大图进行使用,这张大图就是一个图集。这样不但可以减小美术资源的总体积,还可以减少载入内存的操作(图集作为一张整图会被一次性载入到内存中)并提高渲染性能,而且还可以减少维护大量零碎小资源的麻烦。
如图2.12所示的则是一个由Sprite组成的图集。
在NGUI中也有UITexture的概念,这个UITexture从功能用途上和Sprite精灵有很大的相似之处,都是为了显示一些图片资源。它和Sprite 最大的区别在于,UITexture 是一张独立的图,不依托于任何的图集,这张Texture有自己的材质球和Shader,每一个UITexture都将消耗一个DrawCall(不了解的读者可以理解为一个性能消耗单位)去渲染,每一个UITexture都将独立进行加载。
如图2.13中的大背景图就是UITexture。
标签(Label)在NGUI中并不是指一种标记物,而是指一种纯文本的UI元素。凡是由程序在UI上打出来的字,都属于标签的内容。例如,如果你需要在界面上长期地显示一行字:请打开背包进行整理,那么这行字属于一个Label。再比如,如果你需要显示角色的生命值为100/200,这个数字会随着角色的生命值而变化,这个生命值的数字也属于一个标签,然后代码会根据角色的血量去读取并改变这个标签的内容。
如图2.14所示框中所有的文字信息都属于Label。
在制作UI的过程中,不可能所有地方都由美术完成,最典型的例子就是UI上面的文字。很多时候UI上面的文字都是不停地在进行变化,并且没有什么复杂的艺术字效果,不可能全部由美术制作成图片提供给程序,这个时候就需要程序在UI上进行写字。程序在 UI上写字时,就将用到UI字体。
NGUI 的字体分为动态字体和静态字体。程序人员可以选择把某种特殊字体文件中的一些所需的字拿出来形成一张图,然后打字时会从这张图里去调用文字(类似于调用Sprite),这就是静态字体。也可以直接导入字体文件(例如,宋体、楷体等字体文件),打字时只要字体文件里拥有的字都能正常使用,这就是动态字体。当然,NGUI有系统自带的默认动态字体。
如图2.15所示则为静态字体图集,图2.16所示则为动态字体文件(.ttf格式)。
为什么要剖析UI的资源结构?因为通常情况下,策划设计好UI的功能和大概布局之后,美术人员会做出一张 UI的成品效果图,我们称之为 UI设计图。然后,客户端程序需要根据自己的制作方式,告诉美术人员如何分割出相应的UI元素提交给程序,以完成制作。
下面以图2.17所示的UI设计图作为例子来讲解分析。首先说明一点,客户端程序一定要同时拿到UI设计图和UI功能描述文档才能彻底知道这个UI会进行什么样的操作逻辑,此时才能准确地对UI资源结构进行剖析。主要有以下一些方法。
●看设计图,从相关设计文档了解该UI的功能。
在不了解UI功能的情况下,程序只看设计图不一定能准确地明白这个UI的全部用途,为了减少返工,请务必先了解该 UI模块的全部功能。如图 2.17所示,则是一个典型的登录UI。
●观察UI的设计图,判断哪些字是程序可以写的,哪些字是程序写不了的。
在图中我们发现有“登录”“请输入账号”“请输入密码”等Label。其中,“请输入账号”和“请输入密码”两个标签的文字并没有什么特殊的美术效果,完全可以由程序来完成,就不需要美术提供图片资源了。
而“账号”和“密码”两个标签,虽然本图中可以由程序完成,但是如果碰到那种有特殊美术效果(比如,文字上有华丽的渐变和高光等效果,程序是完成不了的)的,则需要让美术提供一张写有相应文字的图片,用Sprite去代替这个Label。
后文我们会详细讲解什么情况下使用Label。
●通过设计图判断哪些是Sprite,充分考虑复用性。
凡是零碎的、小的图片资源,都可以是 Sprite。如图 2.17 中,输入账号密码有一个底框,整个界面又有一个底框,这些都可以让美术人员切成单独的 Sprite,然后由程序来进行拼装。
在分割Sprite时,尽量分割得细一点,如图2.17中所示,我们可以将整个UI的大底框和输入账号密码的两个底框合并在一起切给程序,但是这样将导致这个UI图片无法用于其他地方。如果整个UI的大底框和输入账号密码的两个小底框分开来切,那么以后其他需要用底框的地方,就可以复用图中切出的UI资源。
相同的UI元素只需要一份就够了,例如图中输入账号的底框和输入密码的底框是一样的,于是只需要切出一份就可以了。
后文我们会详细讲解什么情况下使用Sprite和Text ure。
●通过设计图判断出按钮资源的制作方式。
按钮笼统地分有两种形式,一种是普通按钮,也就是一张没有文字的按钮图片,程序人员在需要用时,就在上面写上“确定”等不同的、当前所需要的文字。另一种按钮则是图片按钮(以前旧版本NGUI的ImageButton),这种按钮的特点是整个按钮就是一张图片,它既是按钮也是图片。
如图2.17中所示,登录和注册两个按钮几乎一模一样,只是上面的文字有区别,而“登录”和“注册”这几个文字明显是程序可以写出的文字效果,于是可以让美术人员切出一张普通按钮资源的底图,然后程序再在上面写字。
后文我们会详细讲解什么情况下使用按钮。
●通过设计图判断其他控件。
要比较迅速地结合 UI的功能判断出 UI中的一些其他控件,例如假设这是一个人物生命法力的状态栏,那么一定要区分出UI中是否有用来显示人物生命法力值的进度条,如果有进度条,则进度条需要上面切一条表层条,下面切一个空槽底板条。
后文我们会对相关知识进行详细说明。
在剖析UI资源结构的时候,有无数种方案,每一种方案UI美术人员基本都能完成,程序人员也能完成相应的功能。但是,我们一定要通过充分的分析去使用一种相对更好的方案,这样对项目以后的修改和拓展都有好处。在剖析UI资源结构时一定要秉承以下几个原则:
●尽量保证还原设计图的效果,不损失质量,这是前提。
●尽量发现重复的元件,而且重复的元件只需要一份就足够。
●尽量分割得零碎一点,避免多个元件合并在一起出图,这样对项目不利(后文会详细讲解)。
●尽量使用九宫格来制作比较大的底板、底框等(后文会详细讲解)。
●UI切图全部让美术人员以PNG格式导出。
当美术人员提交给你大量零碎的 UI元件时,就可以开始进行UI的制作了。制作的首要任务是先将资源导入到引擎中去。首先在Unity的Project窗口下的Assets文件夹下面建立一个文件夹,将该文件夹命名为Resources,表示这个项目的资源都放在这个文件夹下面,UI资源也不例外。这个文件夹名字一定要设定为Resources,不能改动。
这里讲一下为什么一定要设定一个名为 Resources 的专门的资源文件夹。Unity 开发中,如果涉及动态加载(在游戏中触发了某个条件才需要加载)的情况,比如需要临时生成一个烟火特效等,都会用到Unity的资源加载方法:Resources.Load();这要求需要被动态加载的资源一定要放在Assets下面一个叫Resources的文件夹中。而UI经常会涉及根据不同情况动态加载UI模块的情况,所以一般情况下,我们都会将UI的资源放在Assets目录下的Resources文件夹中。
但是也不是所有资源都放在Resources文件夹中就万事无忧了。因为Unity在生成游戏安装包时,对于 Resources 以外的文件夹,只会打包场景中用到的资源文件,而对于 Resources文件夹,因为涉及动态地往内存里加载资源,所以Unity会无条件的全部打包。如果不加考量的把所有资源都放到Resources目录下,可能会导致最终得到的游戏安装包体积变大。
这时我们可以在Resources目录下建一个名为UI的文件夹,用来单独存储UI资源,以避免UI资源和其他的角色、特效等资源放在一起难以管理。全部选中美术人员提交的UI元件,一起拖曳到Unity界面中的“Resources\UI\”目录下,等待Unity读取资源之后,我们导入的资源会显示在“Resources\UI”目录下,这样就完成了资源的导入,如图2.18所示。
刚刚我们已经将 UI 元件的源文件全部导入到了 Unity 中相应的文件夹目录下,在 Unity的Project窗口中全部选中刚才导入的UI元件,单击鼠标右键,选择最顶部NGUI菜单,选择Open Atlas Maker(Atlas Maker是NGUI自带的一个UI图片打包工具),这样就能自动将这些UI元件放入到Atlas Maker中,如图2.19所示。
在Mac系统下,右键菜单如果没有NGUI选项,那么可以选中导入的UI元件,在Unity顶部的菜单栏中,选择NGUI菜单,然后选择Open\Atlas Maker即可。
打开后的Atlas Maker界面如图2.19所示。
图2.19中,标号为1的红框是已有图集的选择按钮,如果你需要将这些新导入的UI素材资源全部新增到一个已有的图集里,就可以单击这里。单击后能看到当前项目工程中已有的所有的图集,然后可以选择其中一个图集,此时标号为 2 的红框处的按钮将变成 Add/Update,这样就可以新增或者更新这批资源到已有的选定的图集中了。
图2.19中标号为2的红框是主按钮,当要打包的UI素材资源没有选定打包到某个已有图集中去时,这个主按钮会显示Create,意为用这些资源创建一个全新的图集。如果通过标号1的红框处的按钮选择了一个已有图集的话,这个主按钮将变成 Add/Update,意为新增/更新当前这批UI资源到选中的图集中。更新的机制为同名的Sprite图片将会被替换。
图2.19中标号3处的红框显示的是当前选中的UI图片资源的序号和文件名称,标号4处的红框显示的是这些资源哪些是新增的;哪些是更新的;哪些是已有的。在这里,如果选中了一个已有图集,那么该图集中的Sprite也会一起显示出来,如图2.20所示。在图2.20中,红框1 则表示当前选中了一个已有的名为FantasyAtlas的图集。红框2 是编辑图集和新建图集的按钮。红框3的按钮由Create变为了Add/Update。红框4显示出了该图集已有的Sprite,在最尾部有一个删除按钮,单击之后,将会从这个图集中删除该Sprite。如果此时单击Add/Update按钮,那么Sprites列表中尾部标记为绿色的Add的精灵图片将会被新增到这个图集之中。
如果需要更新现有图集中的某一个精灵,则将新的精灵图片文件的名字设为和它要替换的精灵的名字一样,然后按照以上步骤选择它要替换的精灵所在的图集,单击Add/Update即可实现直接替换资源。这在项目开发中是非常实用的,当美术人员希望修改UI资源、用更新的UI资源替换之前的旧资源时,这个自动更新功能将会让程序员非常方便。
下面继续创建属于我们自己的第一个图集,当打开Atlas Maker之后,我们看到的是图2.19所示的界面。我们需要创建一个全新的图集,所以单击Create主按钮,然后会弹出Save As对话框,将路径定位到Resources\UI目录下,然后将图集的名称改为“MyFirstAtlas”,单击“保存”按钮即可,如图2.21所示。注意,不要改变文件的后缀名,文件保存后是一个Prefab。
单击“保存”按钮之后,我们可以看到Atlas Maker界面已经变成了如图2.22所示的情况,这表明图集已经创建成功,中间的主按钮变成了View Sprites,单击后可以预览该图集中所拥有的精灵。
关闭 Atlas Maker 界面,然后注意看 Project 窗口中,Resources\UI 目录下除了我们之前导入的 UI图片资源以外,多出了 3个名为“MyFirstAtlas”的文件,如图 2.23所示。这 3 个文件是一个图集必须具备的 3 个文件:图集的贴图、图集的材质球和图集的预设体。其中,第一个球形图标的 MyFirstAtlas 文件为图集的材质球;第二个蓝色方块的文件为图集的预设体;第三个图片缩略图文件则是图集的贴图,也就是精灵合成为一张整图之后的图片。
至此,我们的第一个图集就算制作完成了,这个图集在后面制作UI时就可以直接使用了。针对Atlas,还有很多功能和用法,例如九宫格等,我们会在本书的后半部分讲到。
特别注明:在制作完UI图集之后,我们可以将之前导入Unity的UI资源源文件删除以减小资源量。
在游戏的项目开发中,字体是经常会用到的东西,因为游戏中不论是聊天、公告、提示语还是界面显示,都会涉及用程序来写字。一般来说,会有系统默认字体供我们使用,但是出于以下两个原因我们经常会需要制作独特的字体。
●系统字体的风格和美观程度等无法满足我们的需求。
一般来说,系统字体都比较死板、生硬,风格单一,经常无法满足项目需求。例如,我们希望游戏中所有文字都使用楷书来突出中国风,那么则需要我们自己植入楷书字体。再例如,我们需要在某些地方显示一些造型独特的字体,更需要制作我们自己独特的字体文件才能满足这种需求。
●应对系统字体丢失的情况。
某些玩家(特别是安卓玩家)如果经常从网上下载一些个性化的字体管理软件,会很容易导致系统字体丢失,这种情况一旦发生,会导致游戏内所有的文字都不能正常显示。为了以防万一,我们需要植入一套自己的字体在游戏资源包内部。
我们在2.2节中已经介绍了什么是静态字体和什么是动态字体,这里我们来了解一下什么情况下需要静态字体,什么情况下需要动态字体。
当有大面积的字体需求,并且需要的文字几乎涵盖大部分汉字时,我们就需要制作动态字体。与其说是制作动态字体,不如说是植入动态字体,因为在新版的NGUI中,制作动态字体只需要导入一个TTF格式的字体文件即可。
当在某些地方有特殊字体的需求,并且这种字体显示的文字有限时,例如受到伤害时,角色头顶需要飘出一个有艺术效果的数字来表示伤害量,这种字体效果只会显示0~9共10个数字而已,其他地方都用不到这种字体,那么这个时候我们就可以为它制作一个静态字体。
具体来说,静态字体和动态字体有以下实质区别。
●静态字体中,如果需要用到的文字不多,打成图集后资源量往往比动态字体小,一个动态字体的TTF格式文件一般为3~6MB。
●静态字体可以通过提供一张自定义的含有所需文字的图片和一个配置文件(记录图片哪一块是哪个字的文件)来完成。动态字体只能通过导入整个TTF格式的字体文件完成。
●静态字体中的字一般非常有限,只有极少数的字(否则图片资源会非常大),所以应用范围非常小,几乎很少用到静态字体。而动态字体几乎包含所有的文字,被广泛运用。
静态字体曾经风靡一时,原因是那时候NGUI旧版本对动态字体支持不是很好,所以很多时候得依赖静态字体。目前NGUI对动态字体支持很好,所以静态字体的应用就变得很少,只有在特殊情况下才使用。
要制作静态字体,需要将字筛选出来打成一个图集,并生成一份记录其中哪一块是哪个字的配置文件,这时可以借助一个名为BMFont的软件将其制作出来。制作出这两份文件之后,导入到Unity里。
在Unity界面中,在Project窗口内单击鼠标右键,选择NGUI菜单,选择Open BipMap Font Maker,打开流程和打开Atlas Maker极其相似。Mac电脑可以通过Unity顶部菜单栏中的NGUI菜单打开。
然后会弹出如图2.24 所示的界面,在Type 中选择Imported Bitmap,然后在Font Data中选择我们之前制作出的那个记录文字位置信息的配置文件(最好是TXT格式),在Texture中选择我们之前制作出的那个文字图集,然后单击主按钮Create the Font,即可创建出一个静态字体,创建出来的字体文件和制作图集得到的文件类似。制作好后,以后我们需要用字体的时候,选择这个字体的预设即可。
注意,制作完成后不要删除导入的那张文字图集和文字位置的配置文件的源文件,如果删除将会导致字体读不出文字。
在新版本的NGUI中(比如,3.6以后),制作动态字体非常简单,只需要从网上下载一个TTF格式的字体文件即可。然后将这个字体文件导入Unity中就算完成了,以后需要用字体的时候,就能直接调用这个字体。
注意,字体文件要选择简体中文的,TTF文件大小一般为3~6MB,如果远远超出了这个数,一般来说很有可能是字体中包含了很多种语言。
制作UI时,首先我们要创建UI的“根”。在Unity顶部NGUI菜单中选择Create,然后选择2D UI,如图2.25 所示。
创建完成后,我们能看到图2.26所示的景象,在Scene窗口中,NGUI自动生成了一个名为UI Root 的物体,其中带有一个Camera 作为子物体。
这个新生成的Camera,是NGUI生成的专门用来渲染UI的相机,当我们生成NGUI的UI Root时,就自动将生成的UI的layer设为了第8层。在这个相机中,只能看见第8 层的物体,也就是只能看见UI。因为是2D UI,所以我们从图中可以看到相机是正交相机。
图2.26中红色的矩形是相机的视窗大小比例,它会根据Game 视图中的屏幕长宽比设置自动调整。
创建3D UI的过程和创建2D UI的过程类似,创建出来的3D UI如图2.27所示,NGUI依然自动生成了一个名为UI Root的物体,并带有一个Camera 子物体,这个原理和2D UI类似,其中最大的区别就是相机的模式。3D UI的相机在Scene视窗中是一个正交摄像机,将会支持UI的三维透视效果。
在我们创建的UI中,可以发现UI Root物体和Camera 物体上面都带有NGUI特有的脚本组件,其中 UI Root 物体上带有 UIRoot 和 UIPanel 两个组件,而子物体 Camera 带有一个UICamera组件,这几个组件都是NGUI体系中比较核心的组件,下面我们来简单了解一下。
1.UIRoot组件
UIRoot组件总是出现在NGUI的UI“树”的最顶层,也就是那个“根”物体中。它的作用是缩放UI。我们在让美术人员作图时知道,UI一般都是以像素作为单位,比如1920*1080等,而Unity中则是以米为单位,如果一个100*100像素的UI元件放入到一块1000*1000分辨率的屏幕中,按理说这个UI元件应该是屏幕大小的1%,但是因为Unity中的单位是米,所以它会从100*100像素的大小变为100*100米,会导致一个小UI元件变得非常之巨大。这个时候UIRoot会通过屏幕来缩放UI控件,让UI控件从视觉上是正常的。
在UIRoot组件中,它提供了3种缩放的方式,也就是UIRoot组件下的Type值。这3种方式分别为PixelPerfect、FixedSize、FixedSizeOnMobiles。
PixelPerfect是指永远保持像素大小不变,比如一张100*100像素的图片,在500*500分辨率的屏幕上,它是100*100像素,在1000*1000分辨率的屏幕上,它依然还是100*100像素,因为它的源文件就是这个大小,而PixelPerfect让它一直保持这个大小。这样就可以让UI的图片永远是最清晰的,但是会导致分辨率高的屏幕下UI显得特别小;分辨率低的屏幕下 UI显得特别大。
FixedSize是和上一种缩放方案完全相反的方案。在FixedSize下,NGUI将不再保护图片的原尺寸,只会关心 NGUI 自己所需要的缩放参数,这种模式下必须设置 UIRoot 的ManualHeight值,然后NGUI会将所有的控件按照和这个值的高度比例进行缩放。例如,设置ManualHeight为1000,然后一张100*100的图片在高度为1000的屏幕分辨率下占1/10的高度,那么当UI放到一个分辨率为500*500的屏幕上时,它依然占1/10的高度,只不过图片尺寸被自动放缩为50*50,这样就保证了UI和屏幕分辨率的比例是一定的。
FixedSizeOnMobiles是两种方案的结合体,它会让UI在PC、Mac、Linux系统下自动采用PixelPerfect,而在移动设备上自动采用FixedSize。
如果没有选择 FixedSize ,那么必须设置另外两种缩放模式下的 MinimumHeight 和MaximumHeight 两个值,代表最大高度和最小高度。例如选择 PixelPerfect 模式,将MinimumHeight设置为720,将MaximumHeight设置为900,那么在一个分辨率为800*600的屏幕上,因为屏幕分辨率的高度小于UIRoot里的最小高度,UIRoot就会按照FixedSize模式下ManualHeight为720的情况进行处理;同理,如果将UI放到一个分辨率为1920*1080的屏幕上,因为该屏幕分辨率的高度1080大于设置的900,于是UIRoot就会按照FixedSize模式下ManualHeight为900的情况进行处理。
值得注意的是,在3.7.0以后的NGUI上,UIRoot的缩放模式改为了。
●Flexible,等同于上文讲到的PixelPerfect。
●Constrained,等同于上文讲到的FixedSize。
●ConstrainedOnMobiles,等同于上文讲到的FixedSizeOnMobiles。
功能上几乎完全一样。
2.UIPanel组件
如图2.28所示,UIPanel有很多属性。其中,Alpha属性顾名思义是透明度,默认为1不透明。它将控制它旗下所有Widget(所有的UI控件都将带有Widget,因为它们都继承自Widget)的透明度,也就是它会让它的子物体里的所有UI控件都一起发生透明度变化,可以用来做整个UI的淡入淡出以及隐藏等。
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的情况时会做出提醒,如图2.29红框部分所示。
Clipping是剪辑视窗的功能,它将可以让一个面板只显示某一块区域,关于这部分知识后文我们再讲解。
在高级选项中,我们讲解一些初学者需要了解的。Render Q可以理解为渲染顺序,默认为自动设置。这个选项在和粒子系统结合使用时会有影响,我们后文会说明。如果该Panel下的UI需要被灯光影响到(NGUI的UI是默认不接收灯光照射效果的),需要勾选Normals。如果该Panel下面所有的UI控件都不会被移动,那么可以勾选Static来将它们设置为静态的,这样会导致该Panel下所有的控件都将忽略位置、旋转、缩放的操作,永远保持不动。虽然这样可以提高一些性能,但是慎重使用。
单击Show Draw Calls按钮,可以看到该Panel下所有的DrawCall消耗情况,如图2.30所示。
3.UICamera组件
图2.31所示为UICamera组件的截图,UICamera这个组件的核心作用是:让带有这个组件的摄像机渲染出的物体能够接收NGUI的事件。如果我们自己创建了一个物体,并且希望对这个物体使用一些 NGUI 中的事件,例如 OnPress()、OnDrag()等,就需要为渲染这个物体的摄像机添加UICamera组件。
在UICamera中,大部分设置我们都不需要去操心,它让我们的事件支持多点触摸、鼠标键盘触摸屏等事件的接收。但是要注意的是EventMask 这个选项,这个 EventMask 和相机中的 CullingMask 非常相似,相机的 CullingMask 是为了选择渲染那些层的物体,这里的EventMask是为了选择接收那些层的物体的事件。UICamera会默认只接收我们创建UI时被自动设置的那个layer,但是,如果我们在制作UI过程中,在创建UI后因为某些原因修改了UI的层,一定要将UICamera的EventMask修改过来,否则将会发现,我们单击UI没有反应,因为它接收不到这个layer的物体的事件。
关于这 3 个最基础的控件讲了这么多,其中有很多都是较少用到,主要目的是加快对NGUI概念的形成。具体在需要的时候应该进行什么样的操作,我们后面的一些实战内容中会讲到。
先创建一个2DUI(创建方法上文已讲过),然后在2DUI的“根”UIRoot下创建两个精灵(创建方法后面会详解)。然后得到的效果如图2.32所示。
从图2.32中可以看到,创建的两个Sprite为两个按钮图片,它们的位置在UIRoot的红框(视窗)上,也就是Sprite的z轴、相机的z轴、UIRoot的z轴都为0,因为2DUI都是纯粹的2D图片按层次显示,不会出现三维立体效果,所以都是直接紧贴着视窗,只要UI控件在UIRoot的红框范围内,那么UI就能够正常显示在Game上。在Game视图中,我们看到的景象如图2.33所示。
2DUI最本质的意义是:UI摄像机是一个正交摄像机。
同上2.6.1小节一样,先创建一个3DUI,然后在“根”下面创建两个Sprite,得到如图2.34所示的景象。
从图2.34中可以看到,在3DUI下,创建的UI控件都在一个三维立体空间中,摄像机是一个透视的摄像机,这和2DUI有着截然不同的区别,因为2DUI是一个正交摄像机。
3DUI中UIRoot的坐标点如图2.34所示,是在三维空间的一个点上,这个位置是创建UI时自动定义好的,以后创建的UI控件都会自动地在这个点所在的面上生成(自动统一到UIRoot的z轴,因为Sprite属于UIRoot的子物体),所以图2.34中UIRoot根物体和两个创建的Sprite的z轴都为0,而Camera的z轴为-700。
我们在图2.34生成的两个Sprite用3DUI做出的效果,在Game视图里看,和2DUI几乎是一模一样的,如图2.35所示。
但是需要注意的是,如果需要将2DUI改为3DUI,不是简单地将摄像机改为透视模式就行了,在NGUI 3.6.0 以后的某些版本中,这样会导致看不到任何UI控件(这些版本的2DUI的控件和Camera、UIRoot三者在同一个z轴面上,而变成3D摄像机后是看不到和摄像机同z轴的物体),如果将3DUI的摄像机直接改为正交模式,也并不能简单地变成2DUI,因为正交相机的Size并不和NGUI默认的值一样。所以,在进行UI开发时,最好先思考一下将要使用2D还是3DUI更好。
上文中我们讲解了2DUI和3DUI的原理,那么在实际的项目开发中,如何来判断应该使用哪一种UI呢?有以下一些规律可以参考。
(1)新版本的NGUI对3DUI支持很好,如果3DUI和2DUI选择哪一个都行的情况下,建议选择3DUI,扩展性更强。
(2)如果出现 UI 不允许有远近透视的大小变化,必须选择 2DUI。例如,角色头顶的血条,在人物跑远了之后如果血条并不会变小,这时血条就必须用2DUI做。
(3)如果要出现UI有三维变换的效果,例如,由远及近的变大、三维旋转等,就必须用3DUI。
(4)无法明确知道应该用哪一种UI的情况下,建议选用3DUI。
(5)不论用哪一种UI,其实本质上只是一个摄像机的区别,基本上都能实现UI效果,只是需要的处理不一样,所以,如果选择错了UI模式也不用太着急,总有很多办法来解决的。
深度的概念将会一直伴随着UI的制作过程,是UI中一个非常重要的概念。我们在2.5.3小节中讲解UIPanel时已经讲解了深度的概念,这里我们再强化一下对深度的理解。在老版本的NGUI中,UI的显示层次关系是依靠z轴进行的。在新版本的NGUI中,所有UI的z轴都被统一,然后用深度来决定和管理显示的层次关系。关于深度,我们要记住一下关键点。
(1)每一个UIPanel和每一个UI控件都一定会有一个Depth,深度值大代表显示的优先级高(会越趋向于在界面更上层显示)。
(2)Depth 决定的是 UI 的显示层级关系,一个 UI 控件是否显示在最上层是由它所属的Panel的Depth和它本身的Depth决定的。一般情况下,属于低Depth的Panel的控件,不管这个控件本身的Depth为多少,它都将显示在高Depth的Panel的控件后面(被高Depth的Panel遮住)。
(3)尽量不要让Panel之间共享同一个Depth,这样会导致性能消耗增加。
(4)制作 Panel和UI控件时,记得考虑一下它所属的panel和它自身的Depth是否能让它显示在正确的层次关系上。
我们在场景中的每一个Camera也有一个渲染深度,如图2.36所示。
在前文中我们学习到NGUI创建时,都会创建一个它独有的相机。这个相机其实就是Unity中普通的Camera,然后为其附加了一个UICamera的组件。需要注意的是,所有的Camera也都有一个Depth,这个Depth会影响到UI中的Depth,特别是场景有多个Camera来渲染不同层次的UI时,这个影响会比较大。具体我们得遵循以下这些规律。
(1)相机的Depth永远是最高级的,也就是高Depth相机所看到的画面,永远在低Depth相机所看到的画面之上。
(2)如果需要相机有视觉穿透效果(只渲染所看到的东西,其他地方透掉显示其他相机所看到的画面),需要将相机的ClearFlags设置为DepthOnly。
(3)并不是只有负责渲染NGUI的相机的Depth会有影响,所有的相机(比如默认存在的渲染场景的MainCamera)的Depth都受此规律影响。例如,如果将照射UI的摄像机的深度设为0,然后将照射场景的相机深度设为1,那么,将看到场景把所有的UI遮住。
(4)创建UI时,UIRoot下生成的相机默认Depth是比场景中的相机深度高的,不过当场景内有多个摄像机时,一定要管理好每个摄像机的ClearFlags和Depth。
(5)当场景内有多个摄像机时,一定要检查摄像机的CullingMask不要渲染重复的Layer,否则可能导致显示双重画面。如图2.37所示,UI画面被两个相机同时看到,显示了两份(因为两个相机所在的位置不一样,所以看到的大小会不一样)。