上一节,我们大概的了解了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文件,我们一起看下效果吧!下一节准备开始讲解网络管理器的使用方法,尽可能我会为大家在这个项目基础上,继续讲解! 





