Cocos2d-x3.2教程——【我所认识的Cocos2d-x】五、UI管理器使用详解及CocosStudio基本运用

上一节,我们大概的了解了UI管理器的搭建及基本上的运用,本节就详细的使用及CocosStudio做一些讲解,图片可能后后期挂上链接。
本篇所用的Cocos2d-x版本为:Cocos2d-x 3.2
编译器版本VS2013
Cocos Studio 1.5
本教程使用的图片资源来源于网上,如果侵犯了您的权利,请及时通知,我将及时将资源删掉。

Cocos2d-x3.2教程——【我所认识的Cocos2d-x】
五、UI管理器使用详解及CocosStudio基本运用
首先在我们昨天创建工程的基础上,我们需要创建一个CocosStudio工程,并将资源文件导入到创建好的CocosStudio工程下。 我们先将公用头文件类写出PublicHeaderFiles.h

#ifndef__PUBLIC_HEADER_FILES_H__
#define__PUBLIC_HEADER_FILES_H__
 
#include"uimanager/UIManager.h"
 
enumLayer_Name
{
       LN_TEST_1 = 0,
       LN_TEST_2,
       LN_LOGO,
       LN_MENU,
       LN_CONFIG,
       LN_GAME,
};
#endif     //__PUBLIC_HEADER_FILES_H__

然后先尝试制作一个基本的Loading页面。     <img title = '1.jpg' src='http://cdn.cocimg.com/bbs/attachment/Fid_41/41_339298_a87fe064fb04f20.jpg' >     因为Loading可以变相的当作禁止触摸层,所以我将交互点开,并将Loading层级在项目里设置比其它层都高,所以当Loading出现的时候,由于点开交互和CocosStudio交互特性,将会吞掉Loading层下的所有交互事件。    <img title = '2.jpg' src='http://cdn.cocimg.com/bbs/attachment/Fid_41/41_339298_ead37fd22a966fb.jpg' > 
添加一张图片作为Loading图使用    <img title = '3.jpg' src='http://cdn.cocimg.com/bbs/attachment/Fid_41/41_339298_e92453f5117efa2.jpg' >     然后再添加一个层容器,作为遮罩层    <img title = '4.jpg' src='http://cdn.cocimg.com/bbs/attachment/Fid_41/41_339298_979abc23dfa7e1b.jpg' >     <img title = '5.jpg' src='http://cdn.cocimg.com/bbs/attachment/Fid_41/41_339298_f5053e0cbe053b0.jpg' > 
这里需要注意层级,层级越高,优先在前面显示,    如果说我的Loading图片层级在0,遮罩层层级在1,那么遮罩层将会在Loading图片前面,这不是我们想要的效果,所以修改下层级,将Loading图片层级放在2,遮罩层层级放在0,那么我们的Loading图将会在遮罩层上面显示,就跟上图一样的效果。    那么开始写Loading类 UI_Loading.h  
#ifndef  _UI_LOADING_H_
#define  _UI_LOADING_H_
 
#include"PublicHeaderFiles.h"
 
classUI_Loading :public BaseLayer
{
public:
       //初始化;
       virtual bool init();
       //创建;
       CREATE_FUNC(UI_Loading);
       //重载;
       virtual void showUI();
public:
       //studio层;
       Layer*                         m_pUiLayer;
       //studio布局文件;
       Layout*                        m_pWidget;
       //Logo;
       ImageView*          m_pLoading;
};
#endif //_UI_LOADING_H_

UI_Loading.cpp

#include"UI_Loading.h"
 
//初始化;
boolUI_Loading::init()
{
       if (!Layer::init())
       {//Layer初始化失败;
              return false;
       }
 
       m_pUiLayer = nullptr;
       m_pWidget = nullptr;
       m_pLoading = nullptr;
 
       return true;
}
//显示UI;
voidUI_Loading::showUI()
{
       if (!m_pUiLayer)
       {
              m_pUiLayer = Layer::create();
              this->addChild(m_pUiLayer, 3,0);
       }
       if (!m_pWidget)
       {
              m_pWidget =static_cast<Layout*>(GUIReader::getInstance()->widgetFromJsonFile("UI_GameLoading.json"));
              m_pUiLayer->addChild(m_pWidget);
              m_pLoading =static_cast<ImageView*>(Helper::seekWidgetByName(m_pWidget,"Image_Loading"));
              m_pLoading->runAction(RepeatForever::create(RotateBy::create(0.5f,180.f)));
       }
}

OK,Loading类暂时就创建好了,我们将它填入的UI管理器的Loading设置里面。在GameMain类中的初始化init函数里填入。
//初始化;
boolGameMain::init()
{
       if (!Layer::init())
       {//图层初始化失败;
              return false;
       }
       //设置UI管理器与管理器连接;
       GET_T_SM(this);
       //逻辑回调地址;
       SEL_CallFuncND t_Logic =callfuncND_selector(GameMain::setUILayerLogic);
       //绘制回调地址;
       SEL_CallFuncND t_Drwa =callfuncND_selector(GameMain::setUILayerDraw);
       //设置UI管理器与管理器逻辑连接;
       GET_G_LOGIC(t_Logic, t_Drwa);
       //加载UI管理器;
       this->addChild(GET_G_UI(), 0);
       //创建Loading层;
       UI_Loading* loadingLayer =UI_Loading::create();
       //设置Loading层;
       GET_G_UI()->setLoadIngLayer(loadingLayer);
       loadingLayer->showUI();
       //设置业务 执行逻辑——LN_LOGO;
       setUILayerLogic(nullptr, (void*)LN_LOGO);
       //初始化成功;
       return true;
}

在准备编译看效果前,我们首先要做的就是,将CocosStudio里面的资源文件,同样的拷贝到Cocos工程资源目录文件下,并且需要将CocosStudio工程下的Json文件夹下,对应你需要放入程序的xxxx.json,放入到Cocos工程资源目录文件下,千万不要改逻辑,直接扔里就可以了,这个地方以后会讲解,先能用就好。我们编译下看眼效果!


OK,Loading搞定了,那么继续往下开始。一般情况,项目都有这些公共的类,Logo类,Menu类,Config类,Gameplay类这些基本类,下面我们简单的实现下:同样,在studio工程,和cocos工程一起来
为了方便资源调用及统一管理,我专门创建了ResourcePath类,来放置资源路径。然后公用头文件类将引用ResourcePath.h,这样只要我们引用公用头文件就可以使用了,很方便。

#ifndef__PUBLIC_HEADER_FILES_H__
#define__PUBLIC_HEADER_FILES_H__

#include"uimanager/UIManager.h"
#include"ResourcePath.h"

enumLayer_Name
{
       LN_TEST_1 = 0,
       LN_TEST_2,
       LN_LOGO,
       LN_MENU,
       LN_CONFIG,
       LN_GAME,
};
#endif     //__PUBLIC_HEADER_FILES_H__

ResourcePath.h

#ifndef__RESOURCE_PATH_H__
#define__RESOURCE_PATH_H__
 
#define           PNG                                   ".png"
#define           JPG                             ".jpg"
#define           PLIST                          ".plist"
#define           JSON                           ".json"
 
 
#define           RES_LAYOUT                    "UI_"
#define           RES_UI_LOADING             RES_LAYOUT "GameLoading" JSON
#define           RES_UI_LOGO                   RES_LAYOUT "Logo" JSON
#define           RES_UI_MENU                  RES_LAYOUT "Menu" JSON
#define           RES_UI_CONFIG        RES_LAYOUT "Config" JSON
 
#define           RES_LOGO                 "000_1"
#define           RES_MENU_1                    "001_1"
#define           RES_MENU_2                    "001"
#define           RES_CONGIF                     "002"
 
#endif//__RESOURCE_PATH_H__

因为我们是测试的项目,图片资源虽然很少,但是要做到用哪些资源加载哪些资源,不要浪费内存。在管理器GameMain.cpp中业务处理函数添加如下代码:

//逻辑业务处理;
voidGameMain::setUILayerLogic(Node* pSender, void* cIndex)
{
       //获取业务索引;
       int m_iIndex = (int)cIndex;
       //创建基类;
       BaseLayer* temp = nullptr;
       vector<string> t_vTexture2D_List;
       //选择业务;
       switch (m_iIndex)
       {
       case LN_TEST_1:
              //测试业务1;
              temp = Test_Layer_1::create();
              break;
       case LN_TEST_2:
              //测试业务2;
              temp = Test_Layer_2::create();
              break;
       case LN_LOGO:
              //创建LOGO;
              temp = UI_Logo::create();
              t_vTexture2D_List.push_back(RES_LOGO);
              break;
       case LN_MENU:
              temp = UI_Menu::create();
              t_vTexture2D_List.push_back(RES_MENU_1);
              t_vTexture2D_List.push_back(RES_MENU_2);
              t_vTexture2D_List.push_back(RES_CONGIF);
              break;
       default:
              break;
       }
       //设置绘制索引;
       temp->setClassIndex(m_iIndex);
       //UI管理器加载UI层:
       GET_G_ADD(temp, t_vTexture2D_List);
}
//绘制业务处理;
voidGameMain::setUILayerDraw(Node* pSender, void* cIndex)
{
       //获取业务索引;
       int m_iIndex = (int)cIndex;
       //选择业务;
       switch (m_iIndex)
       {
       case LN_TEST_1:
              //测试业务1;
              ((Test_Layer_1*)pSender)->showUI();
              break;
       case LN_TEST_2:
              //测试业务2;
              ((Test_Layer_2*)pSender)->showUI();
              break;
       case LN_LOGO:
              //LOGO显示业务;
              ((UI_Logo*)pSender)->showUI();
              break;
       case LN_MENU:
              //MENU显示业务;
              ((UI_Menu*)pSender)->showUI();
              break;
       default:
              break;
       }
}

Logo类代码附上.h

#ifndef  _UI_LOGI_H_
#define  _UI_LOGI_H_
 
#include"PublicHeaderFiles.h"
 
classUI_Logo :public BaseLayer
{
public:
       //初始化;
       virtual bool init();
       //创建;
       CREATE_FUNC(UI_Logo);
       //重载;
       virtual void showUI();
       //显示;
       void showLogoUI();
       //执行下一场景;
       void NextLayer();
public:
       //studio;
       Layer*                         m_pUiLayer;
       //布局文件;
       Layout*                        m_pWidget;
};
#endif //_UI_LOGI_H_

.cpp


#include"UI_Logo.h"
 
//初始化;
boolUI_Logo::init()
{
       if (!Layer::init())
       {
              return false;
       }
 
       m_pUiLayer = nullptr;
       m_pWidget = nullptr;
       //继承BaseLayer,负责动画索引类型;
       m_iActionIndex = GAI_NULL;
 
       return true;
}
//重载;
voidUI_Logo::showUI()
{
       showLogoUI();
}
//显示;
voidUI_Logo::showLogoUI()
{
       if (m_pUiLayer == nullptr)
       {
              m_pUiLayer = Layer::create();
              this->addChild(m_pUiLayer, 3,0);
       }
       //由于studio中的 UI_LOGO 使用了PLIST文件,所以必须要先加载到内存中,否则无法创建成功;
       m_pWidget =static_cast<Layout*>(GUIReader::getInstance()->widgetFromJsonFile(RES_UI_LOGO));
       m_pUiLayer->addChild(m_pWidget);
 
       //执行顺序组合动画 先暂停1.0秒后执行NextLayer函数;
       this->runAction(Sequence::create(
              DelayTime::create(10.0f),
              CallFunc::create(CC_CALLBACK_0(UI_Logo::NextLayer,this)),
              nullptr));
}
//跳转事件;
voidUI_Logo::NextLayer()
{
       //将本页面使用过的资源清掉;
       string s_path = RES_LOGO;
       s_path.append(".plist");
       SpriteFrameCache::getInstance()->removeSpriteFramesFromFile(RES_LOGO);
 
       GET_G_RLOGIC(LN_MENU);
}

那么开始写menu类跟Logo类实际上差不多,复制一份改个名字,节约时间然后Studio这里面需要注意下


首先menu暂为3个层级背景层 层级0滑动层 层级1 滑动层的ScrollView的交互必须点开,否则没有滑动事件!切记 在ScrollView_SelMenu创建6个Button 一会做滑动用菜单层 层级2 里面有个Button 作为config用这里面 我们暂时需要的空间必须要写到代码里面Menu.h

#ifndef  _UI_MENU_H_
#define  _UI_MENU_H_
 
#include"PublicHeaderFiles.h"
 
classUI_Menu :public BaseLayer
{
public:
       //初始化;
       virtual bool init();
       //创建;
       CREATE_FUNC(UI_Menu);
       //重载;
       virtual void showUI();
       //显示;
       void showMenuUI();
       //执行下一场景;
       void NextLayer();
       //菜单事件;
       void Menu_Event(Ref *pSender,Widget::TouchEventType type);
       //测试回调函数;
       void TestRes(Node* pSender, void*cIndex);
public:
       //studio;
       Layer*                         m_pUiLayer;
       //布局文件;
       Layout*                        m_pWidget;
};
 
 
 
#endif //_UI_MENU_H_

Menu.cpp

#include"UI_Menu.h"
#include"UI_Config.h"
 
//初始化;
boolUI_Menu::init()
{
       if (!Layer::init())
       {
              return false;
       }
 
       m_pUiLayer = nullptr;
       m_pWidget = nullptr;
       //继承BaseLayer,负责动画索引类型;
       m_iActionIndex = GAI_NULL;
 
       return true;
}
//重载;
voidUI_Menu::showUI()
{
       showMenuUI();
}
//显示;
voidUI_Menu::showMenuUI()
{
       if (m_pUiLayer == nullptr)
       {
              m_pUiLayer = Layer::create();
              this->addChild(m_pUiLayer, 3,0);
       }
       //由于studio中的 UI_LOGO 使用了PLIST文件,所以必须要先加载到内存中,否则无法创建成功;
       m_pWidget =static_cast<Layout*>(GUIReader::getInstance()->widgetFromJsonFile(RES_UI_MENU));
       m_pUiLayer->addChild(m_pWidget);
 
       auto m_pConfig = static_cast<Button*>(Helper::seekWidgetByName(m_pWidget,"Button_Config"));
       m_pConfig->setTag(10);
       m_pConfig->addTouchEventListener(CC_CALLBACK_2(UI_Menu::Menu_Event,this));
 
       auto m_pButton_1 =static_cast<Button*>(Helper::seekWidgetByName(m_pWidget,"Button_1"));
       m_pButton_1->setTag(1);
       m_pButton_1->addTouchEventListener(CC_CALLBACK_2(UI_Menu::Menu_Event,this));
 
       auto m_pButton_2 =static_cast<Button*>(Helper::seekWidgetByName(m_pWidget,"Button_2"));
       m_pButton_2->setTag(2);
       m_pButton_2->addTouchEventListener(CC_CALLBACK_2(UI_Menu::Menu_Event,this));
 
       auto m_pButton_3 =static_cast<Button*>(Helper::seekWidgetByName(m_pWidget,"Button_3"));
       m_pButton_3->setTag(3);
       m_pButton_3->addTouchEventListener(CC_CALLBACK_2(UI_Menu::Menu_Event,this));
 
       auto m_pButton_4 =static_cast<Button*>(Helper::seekWidgetByName(m_pWidget,"Button_4"));
       m_pButton_4->setTag(4);
       m_pButton_4->addTouchEventListener(CC_CALLBACK_2(UI_Menu::Menu_Event,this));
 
       auto m_pButton_5 =static_cast<Button*>(Helper::seekWidgetByName(m_pWidget,"Button_5"));
       m_pButton_5->setTag(5);
       m_pButton_5->addTouchEventListener(CC_CALLBACK_2(UI_Menu::Menu_Event,this));
 
       auto m_pButton_6 =static_cast<Button*>(Helper::seekWidgetByName(m_pWidget,"Button_6"));
       m_pButton_6->setTag(6);
       m_pButton_6->addTouchEventListener(CC_CALLBACK_2(UI_Menu::Menu_Event,this));
 
}
//跳转事件;
voidUI_Menu::NextLayer()
{
       GET_G_RLOGIC(LN_MENU);
}
//菜单事件;
voidUI_Menu::Menu_Event(Ref *pSender, Widget::TouchEventType type)
{
       switch (type)
       {
       case Widget::TouchEventType::BEGAN:
              break;
       case Widget::TouchEventType::MOVED:
              break;
       case Widget::TouchEventType::ENDED:
              {
                     int tag =((Button*)pSender)->getTag();
                     switch (tag)
                     {
                     case 10:
                            log("Config");
                            {
                                   //由于Config类 是属于Menu下的,所以我将Config加载在Menu上;
                                   UI_Config*temp = UI_Config::create();
                                   this->addChild(temp,4);
                                   //这里是为了测试返回逻辑的函数;
                                   temp->LoadUILogic(this,callfuncND_selector(UI_Menu::TestRes));
                                   temp->showUI();
                            }
                            break;
                     default:
                            log("Button =%d", tag);
                            break;
                     }
              }
              break;
       case Widget::TouchEventType::CANCELED:
              break;
       default:
              break;
       }
}
//测试回调函数;
voidUI_Menu::TestRes(Node* pSender, void* cIndex)
{
       int mes = (int)cIndex;
       //逻辑返回函数;
       switch (mes)
       {
       case 1:
              log("TestRes 1");
              break;
       default:
              break;
       }
}

哦了,由于老传图片有点累,我直接就开始写Config类了,其实大家也不难看出,我一直都是在复制,粘贴而已,多么的便利和快捷!由于我在studio中 将UI_Config的布局层的交互点开了 所以它会吃掉下面的交互事件!!类似于禁止触摸层的效果!Config.h

#ifndef  _UI_CONFIG_H_
#define  _UI_CONFIG_H_
 
#include"PublicHeaderFiles.h"
 
classUI_Config :public BaseLayer
{
public:
       //初始化;
       virtual bool init();
       //创建;
       CREATE_FUNC(UI_Config);
       //重载;
       virtual void showUI();
       //显示;
       void showConfigUI();
       //执行下一场景;
       void TestLogic();
       //菜单事件;
       void Menu_Event(Ref *pSender,Widget::TouchEventType type);
public:
       //studio;
       Layer*                         m_pUiLayer;
       //布局文件;
       Layout*                        m_pWidget;
};
 
 
 
#endif //_UI_CONFIG_H_

Config.cpp

#include"UI_Config.h"
 
//初始化;
boolUI_Config::init()
{
       if (!Layer::init())
       {
              return false;
       }
 
       m_pUiLayer = nullptr;
       m_pWidget = nullptr;
       //继承BaseLayer,负责动画索引类型;
       m_iActionIndex = GAI_NULL;
 
       return true;
}
//重载;
voidUI_Config::showUI()
{
       showConfigUI();
}
//显示;
voidUI_Config::showConfigUI()
{
       if (m_pUiLayer == nullptr)
       {
              m_pUiLayer = Layer::create();
              this->addChild(m_pUiLayer, 3,0);
 
              auto maskLayer =LayerColor::create(Color4B(0, 0, 0, 160));
              this->addChild(maskLayer, 0);
       }
       //由于studio中的 UI_LOGO 使用了PLIST文件,所以必须要先加载到内存中,否则无法创建成功;
       m_pWidget =static_cast<Layout*>(GUIReader::getInstance()->widgetFromJsonFile(RES_UI_CONFIG));
       m_pUiLayer->addChild(m_pWidget);
 
       auto m_pConfig =static_cast<Button*>(Helper::seekWidgetByName(m_pWidget,"Button_Back"));
       m_pConfig->addTouchEventListener(CC_CALLBACK_2(UI_Config::Menu_Event,this));
       
}
//执行下一场景;
void UI_Config::TestLogic()
{
       //测试返回数据1;
       ReturnLogic(1);
}
//菜单事件;
voidUI_Config::Menu_Event(Ref *pSender, Widget::TouchEventType type)
{
       switch (type)
       {
              //触摸事件;
       case Widget::TouchEventType::BEGAN:
              break;
              //移动事件;
       case Widget::TouchEventType::MOVED:
              break;
              //抬起事件;
       case Widget::TouchEventType::ENDED:
              //首先我们会通知config的逻辑加载层,并返回数据;
              this->runAction(Sequence::create(
                     CallFunc::create(CC_CALLBACK_0(UI_Config::TestLogic,this)),
                     DelayTime::create(0.2f),
                     RemoveSelf::create(true),
                     nullptr));
              break;
              //越界事件;
       case Widget::TouchEventType::CANCELED:
              break;
       default:
              break;
       }
       
}

好了,大致的UI管理器的详细使用方法就到这里了,一会我给给大家传一个gif文件,我们一起看下效果吧!下一节准备开始讲解网络管理器的使用方法,尽可能我会为大家在这个项目基础上,继续讲解!

楼主继续啊。。

需要时间啊,这几天,天天跪方便面,需要缓缓礼拜一的吧,网络那边需要好好弄下:10:

楼主加油:7:

开放源码吧,楼主

我是打算开放源码来着,但是我的UI管理器 不向下兼容,我正在解决这个问题。:10:

楼主超高产!已经推荐到Cocos引擎中文官网首页哦!

周六周日 准备休息下 正好准备下 网络管理器的 一些资料
星期一 或许才能发 第六篇

一定要更完哦楼主,这样才有成就感是不是?
加油,等待你的更新!

不错~~~~~~~~~~~~~~~~~~

本来打算是今天 更新网络篇的 但是公司临时有重要工作。只能延后星期二再更新了~
不好意思了~:12:

楼主你的资源在那里弄啊,

百度搜到的:7:

求 Demo 下载地址…