UI框架

为什么要使用UI框架?直接使用NGUI或UGUI一拖一拉直接搭载出界面不就行了?

很多小白在刚学习Unity3D UI的时候都这样想过使用NGUI或UGUI搭载界面。

弱联网手游一般都没什么复杂的界面很轻松一天就把界面搭载好。

 

问题来了

1.如何实现界面间的沟通?例如点击返回按钮,返回上一个界面,点击背包系统,弹出背包。

2.如何实现界面与游戏数据的沟通?例如点击排行榜,能列出最新的排名,点击购买车辆,能扣钱并买入新的车辆。

大部分新手最喜欢的做法就是为每个要触发功能的UI添加一个脚本,然后添加一个public gameobject,

然后拖入触发UI时要控制的object。在脚本的OnClick等函数里实现逻辑功能。

这样做是挺容易。很快花半天时间拖来拖去,把UI要关联的各种物件绑定好。

 

但是接下来的各种问题非常头疼:

1.随着游戏系统的复杂,UI控件越来越多,各个UI直接的通讯,以及UI与GameObject之间的通讯形成一张复杂的蜘蛛网

拖着拖着,有时候都忘了哪个对象跟哪个对象关联了。如果是别人要看程序找半天都找不到UI逻辑的入口。

2.耦合性非常严重,如果要改变需求,更改某个UI或者更改某个游戏对象,那么你需要再手动全部与该对象关联的物件重新更改一次。

3.代码的混乱。这种组织方式十分“不优雅”,看着很乱。

 

鉴于以上各种情况,寻找一种新的,科学的,高效的UI管理方式,

最开始想到的就是大名鼎鼎的MVC模式,用它来管理UI,对MVC模式不熟悉的话效果并不是很好。

找到几个不错的UI框架

1.Unity-UI-Framework的设计与实现 By:王选易 Github

http://www.manew.com/thread-42748-1-1.html

https://github.com/MrNerverDie/Unity-UI-Framework

2.简单、强大的TTUIFramework By:chiuan 游戏蛮牛 (这位的设计思路是参考上面那位作者的)

http://www.manew.com/thread-42929-1-1.html?_dsign=8c9bee85

3.【设计和开发一套自动化UI框架】 By:NPC燕 游戏蛮牛

http://www.manew.com/thread-41889-1-1.html?_dsign=57fa0b1a

 

他们的设计思路都很清晰,做出来的效果也都很强大,都是些游戏界的大牛,但是都有点复杂。

作为菜鸟,需要菜鸟能看得懂的东西。

以下是设计的两个主要方向:

1. UI管理器: 设计一套负责UI之间逻辑的 UI_Manager,各个UI的生成,销毁,切换,都是通过这个Manager单例模式来实现。各个UI间不直接联系。

2. UI 基类: 所有UI都基于一个UIBase基类,每个UI的预设对应一个UIBase子类脚本,UI的基本逻辑在该类中实现,例如:_MenuView.prefab 对应 _MenuView.cs

3. UI 消息中心 :重新实现Unity3D的消息通讯,原有SendMessage效率较低,利用订阅-发布(即观察者模式)重新设计一套通讯中心,所有UI间的通讯,以及UI和游戏层的通讯,皆间接通过MessageCenter来管理。实现解耦。

4. 栈发方式管理UI,利用栈 先进后出的数据结构特性,每次打开一个新的UI,都将它堆入栈,关闭时出栈。这个栈是一个特殊的栈,例如它可以实现,某个不在栈顶的UI,可以“TOP”到栈顶。

 

看过skik老师的,但感觉还是不够完美。大多都是提出接口做基类字典存放面板路径json读取。 使用堆栈模拟父子窗体。 

但是动画这个少一些,还有按钮处理、遮罩这块差的还很多。

 

一个简单易懂的整体框架图

UI框架

介绍一下这个框架图:
1.在图的左边部分UIPaneltype是每个UI面板的类型,对应上述各个面板介绍,在代码中使用一个枚举来存储,每一个枚举类型对应一个面板。再往下是存放面板预设体路径的文件 UIPanelType.json,它是一个Json文件,保存的是每个面板和每个面板预设在工程文件中的路径信息,我们将会解析它来实例化一个个的面板,其中这里面板需要先制作好然后拖到Resource文件下做成一个预设,这样才能加载并实例化。

2.在图的中上部分GameRoot是用来初始化启动一个UI框架的,需要挂载到一个游戏中的物体上,建议是Canvas上。图中的UIManager是整个UI框架的核心管理类,其功能如图中所诉。

3.BasePanel是每个面板的公共基类,这里设置一个公共基类是因为在各个面板都有相似的逻辑处理,比如在图中最右边页面状态流程图所示,每个页面都有其自身的状态,此时,只需要将这些状态封装成函数放在基类中并声明为虚函数,然后在子类中实现即可。

4.图中显示页面的容器栈就是该框架实现的数据结构,介绍如开始核心思想所诉。

5.图中的页面状态生命周期流程图:每个页面都有其自身的生命周期:显示状态、暂停显示状态、继续显示状态和界面退出状态。而每个状态的运用需要配合页面的容器栈来实现

 

理解该框架之后,你不但可以利用该框架为你设计的游戏UI界面的处理服务,而且完全可以在此框架上继续拓展你自己需要的部分,使其更完善。

主要思想:栈的运用。使用一个栈来保存场景中的实例化出来的各个UI界面,使用Push()入栈方法显示栈顶界面,此时栈中其他界面不能交互。当关闭当前界面时使用Pop()弹栈方法关闭并移除当前界面,此时栈顶的元素变成第二个元素也就是第二个界面,该界面就重新获得交互能力。该栈使用一个管理类(UIManager)来进行维护。

想一想,当你制作一个游戏UI各个界面时,本来只想显示任务面板,但是在显示任务面板的同时,背包面板或者其他面板依然可以弹出来并且可以进行点击交互,这样给玩家的体验就太不好了。所以该框架重点在于各个UI界面的显示逻辑,并不在于优美的UI制作(UI的制作就自己动手实现吧)。也就是管理各个UI界面的显示和隐藏,还有控制各个UI界面何时可交互以及何时不可交互。在这里我使用一个类似RPG游戏UI方面来实现,一般来说,一个RPG游戏在UI方面分为以下几个方面:

1.主界面面板:承载主角的基本信息
2.任务面板:用于主角的任务处理面板
3.背包面板:用于存储主角的装备等
4.技能面板:用于存储主角的技能信息等,这里图示同上,我就不给出了

5.战斗:这里的战斗点击之后是主角会进入真实游戏场景中,就不在属于UI方面了,所以这里只是象征性的设计了一个按钮,并没有加以处理

6.商城面板:由于主角购买和售卖装备或物品等,图片同上(这里可以参考我的上几篇博客,其中详细的介绍了背包系统,准备系统和锻造系统。)

7.设置面板:用于设置游戏中的玩家体验效果如音量设置等