浅谈使用NGUI的界面架构(一)

浅谈使用NGUI的界面架构(一)

作者:kUANG tOBY
链接:https://zhuanlan.zhihu.com/p/20943442
来源:知乎

印象中,Unity一直没有一套成熟的界面体系。现在可供选择的不外乎NGUI和UGUI,之前也用过EZGUI和2D ToolKit。

选择了NGUI,很多人说NGUI不好用。一个工具,只要你对它足够熟悉,就一定有一套最适合它的使用方法。当然每个工具都一定有它的无法回避的缺点和硬伤,但大部分人只是使用方式不对罢了,还没到受工具局限性影响的阶段。

选择NGUI作为主要的界面工具主要是基于以下考虑:

1、有较多的文档,新人容易上手
2、功能比较全,一个手游需要的界面功能基本都有
3、有个MVVM工具NData可以和NGUI配合使用,这样可以极大地提高开发效率,适应需求修改。这个后面会详细介绍。


在设计界面架构的时候,主要想实现以下几个目的:

1、把游戏的各个界面模块集中管理,统一调度,但又必须把每个模块之间的耦合性降到最低。这样可以不同的人开发不同的模块,互不干扰,做出来的东西运行起来又不会互相冲突。
2、把界面逻辑和界面版式尽量分离开来,让美术也可以参与界面的修改(事实证明,这个想法最后救了程序的命)。
3、界面模块的开发必须有一套统一的流程,统一的格式,方便不同的人维护。


在具体设计之前,首先要了解NGUI的局限性。


NGUI有很多缺点,最受人诟病的就是性能问题和内存消耗问题。这两个问题都和NGUI的底层渲染机制有关。NGUI的渲染基于每一帧的Mesh重建,把一个UIPanel下的多个使用相同图集的UIWidget合并成一个Mesh,以此来减少draw call。NGUI本身对此做了优化,即如果一个UIPanel下的内容没有变化,就使用缓存的Mesh。但界面往往是不停变化的,这样就不可避免的每一帧都要重建Mesh,从而造成CPU的负担和多余的内存消耗。解决的方法就是把要经常变化和移动的界面放在单独的UIPanel下,去移动和变化UIPanel依附的物体。这样虽然会增加draw call,但节省了重建Mesh的性能损耗。


因为这个问题,我把游戏模块分成一个个不同的页面,每个页面都有一个UIPanel,然后在一个统一的地方调度各个页面,这个统一的地方是一个单例类,叫做MainPageMgr。

每个页面都有一个生命周期,即

出现:准备出现->播放出现动画->动画完毕,展示在目标位置
消失:准备消失->播放消失动画->完全消失


其中出现动画和消失动画由NGUI自带的UIPlayTween组件控制,直接把TweenPosition等脚本贴在UIPanel所在的物体上,让技术美术去调整。我把这一系列动作的逻辑都放在一个TweenPage类里,只要调一个弹出或消失的方法,就让它自动运行这个流程。


TweenPage类中有一个Bring(Boolean isBringIn)方法提供给MainPageMgr调用:

Bring(true)出现
Bring(false) 消失


当MainPageMgr调用一个页面TweenPage的Bring方法时,页面就按照它的生命周期开始运动,并触发相应的回调方法。

TweenPage类中有以下回调接口,供具体的页面实现相关逻辑:

OnPreBringIn 准备弹出的回调
OnBringIn 播放完弹出动画的回调
OnPreBringOut 准备播放消失动画的回调
OnBringOut 完全消失的回调


这样,只需要在具体的页面类中重写这几个接口,就可以在这几个时间点做一些事情。例如在OnPreBring接口中实现页面的数据刷新。
自此,页面TweenPage的框架基本成型,然后是实现MainPageMgr的统一调度。

做法是把每个页面的TweenPage实例都添加到MainPageMgr中,然后在MainPageMgr中为每个TweenPage实例都提供一个弹出方法,如弹出或关闭英雄管理界面BringPageHero(Boolean isBringIn)。这个弹出方法可以根据不同页面的情况设置不同的参数,但都有一个Boolean值表示是让页面出现还是消失,并且都要调用MainPageMgr的BringPage(TweenPage page)方法。

BringPage(TweenPage page)方法主要实现页面的统一调度管理,例如把一个页面显示到屏幕最前面,挡住其他所有页面。

在MainPageMgr中实现List<TweenPage> pageList,用来保存当前已经打开的页面。我把页面设计成叠加遮挡模式,即一个页面弹出会叠在前一个页面上面并挡住它。pageList中就按顺序保存正处于打开状态的页面TweenPage实例。每次打开一个页面,都会给pageList中的所有TweenPage的UIPanel设置一个新的深度,并把当前已经打开的所有页面GameObject的Z轴往前移,这样可以确保夹在两个UIPanel之间的3D模型(如角色模型)显示正常。最后把要打开的页面加入到pageList中,并给它的UIPanel赋值一个当前最大的深度,使其可以遮挡前面所有的页面。让页面消失就使用相反的操作。这些操作都是用MainPageMgr的方法BringPage(Boolean isBringIn)实现。

界面的调度逻辑基本就是这样,现在要加一个新的页面只需要新建一个继承TweenPage的类,贴上UIPanel和其他UIPlayTween组件,并在MainPageMgr中添加一个弹出方法即可。

这里只是提供一个大致的思路,细节就不再深入说明了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值