Cocos2d-x3.2教程——【我所认识的Cocos2d-x】四、Cocos2d-x项目—UI管理器篇

上一节,我们简单的了解了整个游戏程序应该需要的知识,那么本节,我们就详细的了解下UI管理器,UI管理器顾名思义,就是管理UI的。前几节和大家探讨过了,因为个人经历原因,我喜欢直接使用Layer,而不是Scene,所以本篇文章的切换页面都是用Layer实现,而不是Scene。
本篇所用的Cocos2d-x版本为:Cocos2d-x 3.2
编译器版本VS2013

Cocos2d-x3.2教程——【我所认识的Cocos2d-x】四、Cocos2d-x项目—UI管理器篇上一节我们已经大致的搭建出了基础工程,那么下面我们开始一些详细的设置。我们先将需要的组件全部加载进来。

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image002.jpg)

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

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image003.jpg)

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

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image004.jpg)

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

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image005.jpg)

将包含目录设置下


![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image006.jpg)

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

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image007.jpg)

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

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image008.jpg)


编译一下就能看见熟悉的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
、……
好了,基本上我们大概的列出了这几条。
那么我们先看眼代码
我会逐一为大家讲解

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image013.jpg)

首先,作为管理器,我们一定要单例出来!作为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作为第一加载场景。

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image014.jpg)

我们的主管理器,不仅仅要加载UI管理器,还要对数据管理器、网络管理器、数据库管理器等做管理,本节仅仅是对UI管理器的设置。
![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image016.jpg)

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image018.jpg)

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

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image020.jpg)

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

3、
UI
管理器实践:
我们先写个业务类,根据BaseLayer派生出的 Tset_Layer_1

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image021.jpg)
我们继承了并重载了 showUI函数
那么我们看看cpp是怎么实现的

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image023.jpg)
就是一个基础的HelloWorld变异版,只不过添加了一些UI管理器调用方法,方便进行业务之间的跳转和数据上的交互等。那么开始编译吧!!

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image025.jpg)

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

![](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtml1/01/clip_image027.jpg)

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

顶一下:10:

这篇有点乱哈:7:

形乱神不乱!还是那个深深的VV啊!:14:

赞赞赞赞,lz继续啊~:2:

弱弱说一句,论坛有代码高亮功能啊,其实直接插入代码片段比较好吧····
截图还麻烦。

我只是来看看的

:12: 我才知道。。。。。

顶顶顶:14::14::14::14:

h写的很好顶。。。。。

很好的文章,学习了楼主~

尼玛,回复了怎么还看不到,XXXX

写的非常好

支持 顶!!!!!!!

新手 学习哈 是不是就和 用define定义一样,集中到一个头文件中,用的时候就调用这个头文件就可以了?

是的,可以这么理解

赞赞赞赞啊 楼主,学习了:2:

回复什么的。。真好嘛类人

顶顶顶······

萨拉看到积分轮廓就撒地方