cocos2dx 持续学习(三) 场景切换、弹出对话框


一、首先总结一下场景切换,通常来说使用下面类似的代码就可以执行场景切换

Director::getInstance()->replaceScene(TransitionFade::create(0.3f, secondScene::createScene()))

这种情况下会把当前场景释放掉,这在当我不需要回到当前场景的时候是可行的。但是,有很多情形是需要回到当前场景的,比如我自己设计的小游戏中当人物血量为0时,可以重新挑战,这时候需要回退到上一场景,上一场景的一些属性或人物状态我想重用,这时候在场景切换的时候就需要

在secondScene中,当需要切换到其他场景时,使用pushScene把当前场景入栈,

Director::getInstance()->pushScene(TransitionFade::create(0.3f, firstBattleScene::createScene()));

在firstBattleScene想回到secondScene时,使用popScene将之前入栈的场景弹出即可

Director::getInstance()->popScene();


二、弹出对话框

对话框在游戏中使用很普遍,简单的对话可以直接使用Label,对于需要用户选择操作等复杂的对话框,还是需要设计专门的类进行处理。这里的代码参考《cocos2d-x3.x 弹出对话框的设计与实现》,原文链接https://www.2cto.com/kf/201411/352055.html 。由于我使用的引擎是cocos2d-x-3.15.1,程序代码中CC能消掉的要尽可能消掉。例如CCSizeZero,要替换为3.x的语法Size::ZERO,2.x到3.x其他变化,参考文章cocos2dx 2.x到cocos2dx 3.x的一些改变》,原文链接http://blog.csdn.net/u012234115/article/details/39717853。否则有可能会报一个如下错误:

error LNK2019: 无法解析的外部符号 "__declspec(dllimport) void __cdecl cocos2d::CCLog(char const *,...)" (__imp_?CCLog@cocos2d@@YAXPBDZZ),该符号在函数 "private: void __thiscall PopupLayer::buttonCallback(class cocos2d::Ref *)" (?buttonCallback@PopupLayer@@AAEXPAVRef@cocos2d@@@Z) 中被引用


PopuLayer.h代码

#ifndef __PopupDemo__PopupLayer__


#define __PopupDemo__PopupLayer__


#include "cocos2d.h"
//#include "cocos-ext.h"


using namespace cocos2d;
//USING_NS_CC_EXT;
using namespace std;

class PopupLayer :public Layer
{
public:
PopupLayer();
~PopupLayer();


virtual bool init();
CREATE_FUNC(PopupLayer);


public:
//需要重写触摸注册函数,重新给定触摸级别
//virtual void registerWithTouchDispatcher(void);


//重写触摸函数,永远返回 true ,屏蔽其它层,达到 “模态” 效果
bool onTouchBegan(Touch *touch, Event *event);


//构造,并设置对话框背景图片
static PopupLayer* create(const char* backgroundImage);


//设置显示标题文字内容和大小
void setTitle(const char* title, int fontsize = 20);


// 文本内容,padding 为文字到对话框两边预留的距离,这是可控的,距上方的距离亦是如此
void setContentText(const char* text, int fontsize = 20, int padding = 50, int paddintTop = 100);
// 回调函数,当点击按钮后,我们关闭弹出层的同时,需要一个回调函数,以通知我们点击了哪个按钮(如果有多个)
void setCallbackFunc(Object* target, SEL_CallFuncN callfun);
// 为了添加按钮方便,封装了一个函数,传入些必要的参数
bool addButton(const char* normalImage, const char* selectedImage, const char* title, int tag = 0);


//为了在显示层时之前的属性生效,选择在onEnter中动态显示
virtual void onEnter();
virtual void onExit();


public:
void buttonCallback(Object* pSender);
//void buttonCallback(Object* pSender);


// 文字内容两边的空白区
int m_contentPadding;
int m_contentPaddingTop;


Object* m_callbackListener;
SEL_CallFuncN m_callback;

CC_SYNTHESIZE_RETAIN(Menu*, m__pMenu, MenuButton);
CC_SYNTHESIZE_RETAIN(Sprite*, m__sfBackGround, SpriteBackGround);
CC_SYNTHESIZE_RETAIN(Sprite*, m__s9BackGround, Sprite9BackGround);
CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltTitle, LabelTitle);
CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltContentText, LabelContentText);

};

#endif


#ifndef __PopupDemo__PopupLayer__


#define __PopupDemo__PopupLayer__


#include "cocos2d.h"
//#include "cocos-ext.h"


using namespace cocos2d;
//USING_NS_CC_EXT;
using namespace std;




class PopupLayer :public Layer
{
public:
PopupLayer();
~PopupLayer();


virtual bool init();
CREATE_FUNC(PopupLayer);


public:
//需要重写触摸注册函数,重新给定触摸级别
//virtual void registerWithTouchDispatcher(void);


//重写触摸函数,永远返回 true ,屏蔽其它层,达到 “模态” 效果
bool onTouchBegan(Touch *touch, Event *event);


//构造,并设置对话框背景图片
static PopupLayer* create(const char* backgroundImage);


//设置显示标题文字内容和大小
void setTitle(const char* title, int fontsize = 20);


// 文本内容,padding 为文字到对话框两边预留的距离,这是可控的,距上方的距离亦是如此
void setContentText(const char* text, int fontsize = 20, int padding = 50, int paddintTop = 100);
// 回调函数,当点击按钮后,我们关闭弹出层的同时,需要一个回调函数,以通知我们点击了哪个按钮(如果有多个)
void setCallbackFunc(Object* target, SEL_CallFuncN callfun);
// 为了添加按钮方便,封装了一个函数,传入些必要的参数
bool addButton(const char* normalImage, const char* selectedImage, const char* title, int tag = 0);


//为了在显示层时之前的属性生效,选择在onEnter中动态显示
virtual void onEnter();
virtual void onExit();




public:
void buttonCallback(Object* pSender);
//void buttonCallback(Object* pSender);


// 文字内容两边的空白区
int m_contentPadding;
int m_contentPaddingTop;


Object* m_callbackListener;
SEL_CallFuncN m_callback;

CC_SYNTHESIZE_RETAIN(Menu*, m__pMenu, MenuButton);
CC_SYNTHESIZE_RETAIN(Sprite*, m__sfBackGround, SpriteBackGround);
CC_SYNTHESIZE_RETAIN(Sprite*, m__s9BackGround, Sprite9BackGround);
CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltTitle, LabelTitle);
CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltContentText, LabelContentText);






};




#endif


#ifndef __PopupDemo__PopupLayer__


#define __PopupDemo__PopupLayer__


#include "cocos2d.h"
//#include "cocos-ext.h"


using namespace cocos2d;
//USING_NS_CC_EXT;
using namespace std;




class PopupLayer :public Layer
{
public:
PopupLayer();
~PopupLayer();


virtual bool init();
CREATE_FUNC(PopupLayer);


public:
//需要重写触摸注册函数,重新给定触摸级别
//virtual void registerWithTouchDispatcher(void);


//重写触摸函数,永远返回 true ,屏蔽其它层,达到 “模态” 效果
bool onTouchBegan(Touch *touch, Event *event);


//构造,并设置对话框背景图片
static PopupLayer* create(const char* backgroundImage);


//设置显示标题文字内容和大小
void setTitle(const char* title, int fontsize = 20);


// 文本内容,padding 为文字到对话框两边预留的距离,这是可控的,距上方的距离亦是如此
void setContentText(const char* text, int fontsize = 20, int padding = 50, int paddintTop = 100);
// 回调函数,当点击按钮后,我们关闭弹出层的同时,需要一个回调函数,以通知我们点击了哪个按钮(如果有多个)
void setCallbackFunc(Object* target, SEL_CallFuncN callfun);
// 为了添加按钮方便,封装了一个函数,传入些必要的参数
bool addButton(const char* normalImage, const char* selectedImage, const char* title, int tag = 0);


//为了在显示层时之前的属性生效,选择在onEnter中动态显示
virtual void onEnter();
virtual void onExit();




public:
void buttonCallback(Object* pSender);
//void buttonCallback(Object* pSender);


// 文字内容两边的空白区
int m_contentPadding;
int m_contentPaddingTop;


Object* m_callbackListener;
SEL_CallFuncN m_callback;

CC_SYNTHESIZE_RETAIN(Menu*, m__pMenu, MenuButton);
CC_SYNTHESIZE_RETAIN(Sprite*, m__sfBackGround, SpriteBackGround);
CC_SYNTHESIZE_RETAIN(Sprite*, m__s9BackGround, Sprite9BackGround);
CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltTitle, LabelTitle);
CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltContentText, LabelContentText);


};


#endif


PopuLayer.c代码


#include "PopupLayer.h"


PopupLayer::PopupLayer() :
m__pMenu(NULL),
m_contentPadding(0), 
m_contentPaddingTop(0), 
m_callbackListener(NULL), 
m_callback(NULL), 
m__sfBackGround(NULL), 
m__s9BackGround(NULL), 
m__ltContentText(NULL), 
m__ltTitle(NULL) 
{}


PopupLayer::~PopupLayer()
{
CC_SAFE_RELEASE(m__pMenu);
CC_SAFE_RELEASE(m__sfBackGround);
CC_SAFE_RELEASE(m__ltContentText);
CC_SAFE_RELEASE(m__ltTitle);
CC_SAFE_RELEASE(m__s9BackGround);
}


bool PopupLayer::init()
{
/* bool bRef = false;
do
{
CC_BREAK_IF(!CCLayer::init());
this->setContentSize(CCSizeZero);
// 初始化需要的 Menu
CCMenu* menu = CCMenu::create();
menu->setPosition(CCPointZero);
setMenuButton(menu);
setTouchEnabled(true);
bRef = true;
} while (0);
 
return bRef;
*/
if (!Layer::init())
{
return false;
}


this->setContentSize(Size::ZERO);
// 初始化需要的 Menu
Menu* menu = Menu::create();
//menu->setPosition(CCPointZero);
menu->setPosition(Point::ZERO);

setMenuButton(menu);


setTouchEnabled(true);


return true;


}


bool PopupLayer::onTouchBegan(Touch *touch, Event *event){
//
log("PopupLayer touch");
return true;
}




PopupLayer* PopupLayer::create(const char *backgroundImage)
{
PopupLayer* ml = PopupLayer::create();
ml->setSpriteBackGround(Sprite::create(backgroundImage));
ml->setSprite9BackGround(Sprite::create(backgroundImage));
return ml;
}


void PopupLayer::setTitle(const char*title, int fontsize)
{
LabelTTF* ltfTitle = LabelTTF::create(title, "", fontsize);
setLabelTitle(ltfTitle);
}


void PopupLayer::setContentText(const char *text, int fontsize, int padding, int paddingTop){
LabelTTF* ltf = LabelTTF::create(text, "", fontsize);
setLabelContentText(ltf);
m_contentPadding = padding;
m_contentPaddingTop = paddingTop;
}


void PopupLayer::setCallbackFunc(cocos2d::Object *target, SEL_CallFuncN callfun)
{
m_callbackListener = target;
m_callback = callfun;
}


bool PopupLayer::addButton(const char *normalImage, const char *selectedImage, const char *title, int tag){
Size winSize = Director::sharedDirector()->getWinSize();
Point pCenter = Point(winSize.width / 2, winSize.height / 2);

// 创建图片菜单按钮
MenuItemImage* menuImage = MenuItemImage::create(normalImage, selectedImage, this, menu_selector(PopupLayer::buttonCallback));
//CCMenuItemImage* menuImage = CCMenuItemImage::create(normalImage, selectedImage, this, NULL);
menuImage->setTag(tag);
menuImage->setPosition(pCenter);

// 添加文字说明并设置位置
Size imenu = menuImage->getContentSize();
LabelTTF* ttf = LabelTTF::create(title, "", 20);
ttf->setColor(ccc3(0, 0, 0));
ttf->setPosition(Point(imenu.width / 2, imenu.height / 2));
menuImage->addChild(ttf);

getMenuButton()->addChild(menuImage);
return true;
}


void PopupLayer::buttonCallback(Object *pSender){
Node* node = dynamic_cast<Node*>(pSender);
//Node* node = NULL;
log("touch tag: %d", node->getTag());
if (m_callback && m_callbackListener){
(m_callbackListener->*m_callback)(node);
}
this->removeFromParent();
}


void PopupLayer::onEnter()
{
Layer::onEnter();

Size winSize = Director::sharedDirector()->getWinSize();
Point pCenter = Point(winSize.width / 2, winSize.height / 2);

Size contentSize;
// 设定好参数,在运行时加载
if (getContentSize().equals(Size::ZERO))
{
getSpriteBackGround()->setPosition(Point(winSize.width / 2, winSize.height / 2));
this->addChild(getSpriteBackGround(), 0, 0);
contentSize = getSpriteBackGround()->getTexture()->getContentSize();
}
else
    {
Sprite *background = getSprite9BackGround();
background->setContentSize(getContentSize());
background->setPosition(Point(winSize.width / 2, winSize.height / 2));
this->addChild(background, 0);
contentSize = getContentSize();
}


// 添加按钮,并设置其位置
this->addChild(getMenuButton());
float btnWidth = contentSize.width / (getMenuButton()->getChildrenCount() + 1);

Vector<Node *> vecArray = getMenuButton()->getChildren();
Object* pObj = NULL;
int i = 0;


for (auto &e : vecArray)
{
Node* node = dynamic_cast<Node*>(e);
node->setPosition(Point(winSize.width / 2 - contentSize.width / 2 + btnWidth*(i + 1), winSize.height / 2 - contentSize.height / 3));
i++;
}


// 显示对话框标题
if (getLabelTitle())
{
getLabelTitle()->setPosition(ccpAdd(pCenter, Point(0, contentSize.height / 2 - 35.0f)));
this->addChild(getLabelTitle());
}

// 显示文本内容
if (getLabelContentText())
{
LabelTTF* ltf = getLabelContentText();
ltf->setPosition(Point(winSize.width / 2, winSize.height / 2));
ltf->setDimensions(CCSizeMake(contentSize.width - m_contentPadding * 2, contentSize.height - m_contentPaddingTop));
ltf->setHorizontalAlignment(kCCTextAlignmentLeft);
this->addChild(ltf);
}


Action* popupLayer = Sequence::create(//ScaleTo::create(0.0, 0.0),
                                               //ScaleTo::create(0.06, 1.05),
                                               //ScaleTo::create(0.08, 0.95),
                                               ScaleTo::create(0.08, 1.0), NULL);
this->runAction(popupLayer);
}


void PopupLayer::onExit()
{
log("popup on exit.");
Layer::onExit();
}


使用对话框的代码

在firstBattleScene.h中

#include "PopupLayer.h"


声明一个void popupLayer(int pop_serial); 传入参数是为了区分不同情况下,弹出不同的对话框,如游戏通关和游戏失败的对话框的区别。

声明一个PopupLayer* pl 变量


在firstBattleScene.c中

void firstBattleScene::popupLayer(int pop_serial)
{

m_popIsOn = true;

switch (pop_serial)
{
case 1:
// 定义一个弹出层,传入一张背景图
pl = PopupLayer::create("pop-bg.png");
// ContentSize 是可选的设置,可以不设置,如果设置把它当作 9 图缩放
pl->setContentSize(CCSizeMake(640, 300));
pl->setTitle(poem.FontToUTF8("任务失败"));
pl->setContentText(poem.FontToUTF8("探险结束了,请注意躲避亚尔丽塔的飞锤,并尽快去攻击亚尔丽塔的本体,是否重新挑战?"), 20, 60, 250);
// 设置回调函数,回调传回一个 CCNode 以获取 tag 判断点击的按钮
// 这只是作为一种封装实现,如果使用 delegate 那就能够更灵活的控制参数了
pl->setCallbackFunc(this, callfuncN_selector(firstBattleScene::buttonCallback));
// 添加按钮,设置图片,文字,tag 信息
pl->addButton("pop-ok.png", "pop-ok.png", poem.FontToUTF8("确定"), 0);
pl->addButton("pop-ok.png", "pop-ok.png", poem.FontToUTF8("取消"), 1);
// 添加到当前层
this->addChild(pl);

break;
case 2:
pl = PopupLayer::create("pop-success-bg.png");
// ContentSize 是可选的设置,可以不设置,如果设置把它当作 9 图缩放
pl->setContentSize(CCSizeMake(640, 300));
pl->setTitle(poem.FontToUTF8("亚尔丽塔篇"));
pl->setContentText(poem.FontToUTF8("恭喜你成功通关,新的征程,新的伙伴等待你去发掘,期待与你再次相见!"), 20, 60, 250);
// 设置回调函数,回调传回一个 CCNode 以获取 tag 判断点击的按钮
// 这只是作为一种封装实现,如果使用 delegate 那就能够更灵活的控制参数了
pl->setCallbackFunc(this, callfuncN_selector(firstBattleScene::buttonCallback));
// 添加按钮,设置图片,文字,tag 信息
//pl->addButton("pop-ok.png", "pop-ok.png", poem.FontToUTF8("确定"), 0);
pl->addButton("pop-ok.png", "pop-ok.png", poem.FontToUTF8("退出游戏"), 1);
// 添加到当前层
this->addChild(pl);


break;
}
}


之后就可以在合适的位置调用popupLayer弹出对话框了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值