上一节,我们简单的了解了整个游戏程序应该需要的知识,那么本节,我们就详细的了解下UI管理器,UI管理器顾名思义,就是管理UI的。前几节和大家探讨过了,因为个人经历原因,我喜欢直接使用Layer,而不是Scene,所以本篇文章的切换页面都是用Layer实现,而不是Scene。
本篇所用的Cocos2d-x版本为:Cocos2d-x 3.2
编译器版本VS2013
Cocos2d-x3.2教程——【我所认识的Cocos2d-x】四、Cocos2d-x项目—UI管理器篇上一节我们已经大致的搭建出了基础工程,那么下面我们开始一些详细的设置。我们先将需要的组件全部加载进来。

然后通过解决方案将库文件引入进来。

这里面注意下 libuimanager 是我个人自己写的 UI管理器库 同学们自己的项目里是没有的!


然后在我们的工程属性里进行部署

将包含目录设置下

注意$(EngineRoot)cocos\editor-support\uimanager 是我的UI管理器路径 同学们的项目不必填写

然后再通用属性里进行一下引用

编译一下就能看见熟悉的HelloWorld了!
当我们项目搭建完毕,准备开始着手写代码的时候,我们势必要想到一个问题,谁来管理我们这些零散的业务类呢?我个人的第一个项目是没有主程的,小伙伴们都是各自顾及自己的业务,一个劲奋勇拼搏,最后的结果就导致,在整合业务类的时候,各业务类横飞,业务类调用复杂,代码复用率极低且不利于管理,给人的感觉就是我们自己在跟自己打仗。这个时候,我们就需要主程或我们自己跟小伙伴们规范,并设计管理器进行管理。
一、
基础页面类 BaseLayer
那么如何设计基础的页面类呢?
首先,我们就先分析一下基本需求:
1、
基本的公用头文件引用
2、
基本的公用函数接口
A、
初始化
B、
接收数据
C、
逻辑加载
D、
逻辑返回
3、
具体代码
我记得在第二节中就跟大家基础的介绍了下MVC的架构方式,由于严谨的架构MVC方式需要大量的时间,请原谅我,在这里简单的搭建一下。
好了基础页面类 BaseLayer 已经搭建好了,那么我们的UI管理器要怎么弄呢?
二、
UI
管理器类UIManager
1
、UI管理器的基础搭建
第一步,都是先分析,分析我们需要什么!
A
、对所有BaseLayer派生出的业务类进行管理
B
、派生出的业务类可以执行切换页面动画的基本诉求
C
、对资源可实行异步加载
D
、有公用的Loading页面
E
、有公用的禁止触摸层
F
、可以任意获取到管理器中的业务类
G
、设置主管理器监听接口
H
、可返回指定逻辑内容
I
、……
好了,基本上我们大概的列出了这几条。
那么我们先看眼代码
我会逐一为大家讲解

首先,作为管理器,我们一定要单例出来!作为UI唯一的管理器存在!
然后按照代码顺序我为同学们一一解读:
//
初始化;
staticUIManager getGameUIManager();
静态创建一个UI管理器 方便我们随时能找到这个唯一的UI管理器
static UIManager GameUIManager;
//初始化单例;
UIManager *UIManager::getGameUIManager(){ if (GameUIManager == nullptr)
{
GameUIManager = new UIManager();
GameUIManager->loadData();
}
return GameUIManager;
}
//
读取数据;
voidloadData();
通过静态单例调用 进行一些初始化的设置,可以包括心跳设置,支线程管理等
//初始化;
void UIManager::loadData()
{
//UI集合;
m_vAllLayerList.clear();
//资源集合;
m_vAllResList.clear();
//主管理初始化;
m_pGameMain = nullptr;
//逻辑初始化;
m_UILogic = nullptr;
//Loading初始化;
m_pLoadIngLayer = nullptr;
//开关初始化;
m_bLoadIng = true;
//支线程开关初始化;
m_bImgLoad = false;
//资源引用计数初始化;
m_iTextureIndex = 0;
//开启一个时间监听;
this->schedule(schedule_selector(UIManager::ThreadOver));
}
//
加入UI层;
voidaddUILayer(BaseLayer* t_paddUI, vector m_vResList);
管理器加载一个业务类,并对资源执行异步加载,这里尚未对pList文件加以支持。其实这个地方无非就是加载一个Layer,只不过我们是会对它进行一些处理,包括资源的异步加载,UI的压入及管理等。
//加入UI层;
voidUIManager::addUILayer(BaseLayer* t_paddUI, vector<string> m_vResList)
{
//资源纹理初始化;
m_vAllResList.clear();
//资源索引初始化;
m_iTextureIndex = 0;
//资源集合赋值;
m_vAllResList = m_vResList;
//UI压入;
t_paddUI->retain();
m_vAllLayerList.push_back(t_paddUI);
//开启读取页面;
LoadingLayerStart();
//是否开启支线程;
if (m_vAllResList.size() > 0)
{
//支线程;
thread t_Accep(ImgLoadThread, (void*)this);
//线程分离;
t_Accep.detach();
}
else
{
//异步加载完毕;
imageLoadedOver();
}
}
//
重载加入UI层;
voidaddUILayer(BaseLayer* t_paddUI);
管理器加载一个业务类
voidUIManager::addUILayer(BaseLayer* t_paddUI)
{
//资源纹理初始化;
m_vAllResList.clear();
//资源索引初始化;
m_iTextureIndex = 0;
//UI压入;
t_paddUI->retain();
m_vAllLayerList.push_back(t_paddUI);
//开启读取页面;
LoadingLayerStart();
//异步加载结束;
imageLoadedOver();
}
//
执行动画;
voidExecutionAnimation(Gif_Action_Index t_iNum);
新加载的业务类要执行的切换动画,我们BaseLayer里专门设置了动画索引变量,管理器就会根据动画索引变量去执行页面的切换效果,像淡入淡出,像左出右进等基础效果
//
切换UI;
voidSwitchingLayer();
业务类切换函数,主要进行对业务UI类进行切换时的管理,像引用计数,变量变更等
//
删除AT0;
voidDelATLayer0();
删除上一个业务,就是删除上一个业务Layer,每次的新的业务Layer都会被放入后面,那么前面的就是以前的业务,所以删除索引0.
voidUIManager::DelATLayer0()
{
BaseLayer* temp = m_vAllLayerList.at(0);
temp->autorelease();
this->removeChild(temp, true);
m_vAllLayerList.erase(m_vAllLayerList.begin() + 0);
}
//
显示UI;
voidadd_UI();
业务加载完毕,显示通知主管理器进行绘制处理,因为我们管理器操作的是基类BaseLayer,所以并不会调用的真正的业务类,所以这里我做了个小处理,扔回主管理器,让主管理器进行UI业务的处理,包括显示函数;
//显示UI;
void UIManager::add_UI()
{
//关闭读取页面;
LoadingLayerEnd();
auto temp = m_vAllLayerList.at(0);
(m_pGameMain->*m_UIDraw)(temp,(int*)temp->getClassIndex());
}
//
显示UI;
voidadd_UI_2();
业务加载完毕,显示通知主管理器进行绘制处理;
//
设置总管理器连接;
voidsetMainManager(Ref* listener);
设置主管理器地址
//
加载逻辑;
voidLoadUILogic(SEL_CallFuncND method, SEL_CallFuncND drawthod);
设置主管理器逻辑及绘制地址
//
返回逻辑;
voidReturnLogic(int classIndex);
返回逻辑函数,通知主管理执行下一业务等;
//
异步加载;
voidimageLoaded(Texture2D* texture);
异步加载方法
//
异步加载完毕;
voidimageLoadedOver();
异步加载完毕
//
开启读取页面;
voidLoadingLayerStart();
开启Loading页面
//
关闭读取页面;
voidLoadingLayerEnd();
关闭Loading页面
//
支线程静态函数;
staticvoid ImgLoadThread(void* data);
支线程静态方法,切记支线程不能调用主线程UI,否则程序必然崩溃!
//
支线程结束;
voidThreadOver(float dt);
支线程结束,通知主线程进行下一步骤
//
获取层;
BaseLayer*getLayerByName(string LayerName);
通过业务名称获取到相应的业务类
//
设置Loading层;
CC_PROPERTY(Layer*,m_pLoadIngLayer, LoadIngLayer);
//Loading
层开关;
CC_SYNTHESIZE(bool,m_bLoadIng, LoadingOpen);
//
支线程开关;
CC_SYNTHESIZE(bool,m_bImgLoad, ImgLoadOpen);
2
、UI管理器的基础设置
前文经常提到,我已经习惯的将Scene当作管理器来用,而且还是作为唯一的Scene,这个地方其实,我们可以根据需求来做,比如如果您的游戏是基于物理系统来做,那您就搭载一个createWithPhysics,怎么样运用都可以。
我创建了一个主管理器类GameMain,并替代里HelloWorld作为第一加载场景。 

我们的主管理器,不仅仅要加载UI管理器,还要对数据管理器、网络管理器、数据库管理器等做管理,本节仅仅是对UI管理器的设置。


那么图片里出现的宏 其实就是我简单的对UI管理器的封装而已

好了,基础的UI管理器设置完毕了,同学肯定还在云雾之中没有明白吧,那么我们就写几个测试业务进行一下实践吧!
3、
UI
管理器实践:
我们先写个业务类,根据BaseLayer派生出的 Tset_Layer_1 

我们继承了并重载了 showUI函数
那么我们看看cpp是怎么实现的

就是一个基础的HelloWorld变异版,只不过添加了一些UI管理器调用方法,方便进行业务之间的跳转和数据上的交互等。那么开始编译吧!!

OK出现了,那么我们就试验下吧!

效果还不错!下一节我将会更为详细的介绍一下,UI管理器的使用方法及一些注意事项,请原谅我对UI管理器不开源,因为我觉得我写的还是不够好,需要用更多的时间去完善,而且目前只支持VS2013编译器且不向下兼容,在这里给大家道歉了! UI管理器下载地址
http://mobile.qzone.qq.com/l?g=1357&sharekey=3fd05c6f6a9ae607ed135c640e2de218,1


















我才知道。。。。。