cocos2d-x 模态对话框的实现

来源:互联网 发布:div如何调用js函数 编辑:程序博客网 时间:2024/06/03 00:54

心情不好,恩,不扯淡了,直接讲。


==================================

在泰然看了一篇实现模态对话框的文章,写的还不错,然后在其基础上加了我简单加了一层灰色透明背景,这样子界面效果看起来会更友好一点,好吧,原谅我的无耻,原创转载什么的也不在意了,原文在这里,今天感觉有点累,恩,主要是大神不能带我飞了,很是失落,好吧,不说废话了。

在游戏中,我们常常需要实现弹出一个模态对话框,比如说游戏暂停,退出提示对话框等

对话框特点如下:


1.可定制的,比如说背景图,标题,文本,按钮等,根据需要添加和设置

2.需要屏蔽对话框下层的触摸

3.为了友好的效果显示,把不可触摸的部分变为灰色


先来看一张效果图:




为了完成这样一个效果,思路如下:


1.设计一个弹出对话框的类PopupLayer,继承于LayerColor,这样子我们就可以设置背景版透明,看起来好像把对话框下层的变灰暗了


        setColor(ccc3(0,0,0));          setOpacity(128);  


2.添加触摸事件,屏蔽下层触摸,也就是在Layer中设置不向下传递

        //add layer touch eventauto listener = EventListenerTouchOneByOne::create();listener->setSwallowTouches(true);//不向下传递触摸listener->onTouchBegan = CC_CALLBACK_2(PopupLayer::onTouchBegan, this);listener->onTouchMoved = CC_CALLBACK_2(PopupLayer::onTouchMoved, this);listener->onTouchEnded = CC_CALLBACK_2(PopupLayer::onTouchEnded, this);auto dispatcher = Director::getInstance()->getEventDispatcher();dispatcher->addEventListenerWithSceneGraphPriority(listener, this);

3.PopupLayer类 实现 可定制对话框标题,按钮,文本,背景图片等


    //标题    void setTitle(const char* title, int fontsize = 20);    //文本    void setContentText(const char* text, int fontsize = 20, int padding = 50, int paddintTop = 100);    //设置button回调事件    void setCallbackFunc(Ref* target, SEL_CallFuncN callfun);     //添加button    bool addButton(const char* normalImage, const char* selectedImage, const char* title, int tag = 0);

4.按钮回调函数实现也比较简单,首先设置外部的回调对象和回调函数


    Ref* m_callbackListener;    //回调对象    SEL_CallFuncN m_callback;   //回调函数    //设置按钮的回调函数    void PopupLayer::setCallbackFunc(Ref* target, SEL_CallFuncN callfun){    m_callbackListener = target;    m_callback = callfun;      }


然后在PopupLayer类中比如说我们添加一个菜单按钮


 // 创建图片菜单按钮    auto item = MenuItemImage::create(        normalImage,        selectedImage,        CC_CALLBACK_1(PopupLayer::buttonCallBack,this));    item->setTag(tag);

设置button回调函数,然后由这个回调函数去调用外部的button监听函数,然后关闭对话框


//button回调函数    void PopupLayer::buttonCallBack(Ref* pSender){    Node* node = dynamic_cast<Node*>(pSender);    CCLog("【====PopupLayer::buttonCallBack====】touch tag: %d", node->getTag());    if (m_callback && m_callbackListener){        (m_callbackListener->*m_callback)(node);    }    this->removeFromParent();}


5.然后用法也比较简单,如果需要对话框内容显示中文,可以参考:cocos2d-x 3.0 使用Sax解析xml文档(解决中文显示问题)这篇文章

    //弹出对话框    pl = PopupLayer::create("BackGround.png",Size(400,350));    pl->setTitle("title");    pl->setContentText("Are you sure exit?", 20, 60, 250);    pl->setCallbackFunc(this, callfuncN_selector(WelcomeScene::popButtonCallback));//设置按钮回调    pl->addButton("pop_button.png", "pop_button.png", "yes", 0);    pl->addButton("pop_button.png", "pop_button.png", "no", 1);    this->addChild(pl);

外部回调函数实现,根据tag判断点了什么按钮


void WelcomeScene::popButtonCallback(Node *pNode){    CCLog("【=====WelcomeScene::popButtonCallback======】button call back. tag: %d", pNode->getTag());    //exit    if(pNode->getTag() == 0){        Director::getInstance()->end();    }}



恩,思路大概这样子,完整的对话框类如下,亲们可以复制直接使用

#pragma once#include "cocos2d.h"#include "cocos-ext.h"using namespace cocos2d;using namespace cocos2d::extension;class PopupLayer : public LayerColor{public:PopupLayer();~PopupLayer();virtual bool init();CREATE_FUNC(PopupLayer);static PopupLayer* create(const char* backgroundImage,Size dialogSize);//touch事件监听 屏蔽向下触摸bool onTouchBegan(Touch *touch, Event *event);void onTouchMoved(Touch *touch, Event *event);void onTouchEnded(Touch* touch, Event* event);//标题void setTitle(const char* title, int fontsize = 20);//文本void setContentText(const char* text, int fontsize = 20, int padding = 50, int paddintTop = 100);//设置button回调事件void setCallbackFunc(Ref* target, SEL_CallFuncN callfun);//添加buttonbool addButton(const char* normalImage, const char* selectedImage, const char* title, int tag = 0);virtual void onEnter();virtual void onExit();void backgroundFinish();private:void buttonCallBack(Ref* pSender);// 文字内容两边的空白区int m_contentPadding;int m_contentPaddingTop;Size m_dialogContentSize;Ref* m_callbackListener;SEL_CallFuncN m_callback;//set and getCC_SYNTHESIZE_RETAIN(Menu*, m__pMenu, MenuButton);CC_SYNTHESIZE_RETAIN(Sprite*, m__sfBackGround, SpriteBackGround);CC_SYNTHESIZE_RETAIN(Scale9Sprite*, m__s9BackGround, Sprite9BackGround);CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltTitle, LabelTitle);CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltContentText, LabelContentText);};

cpp文件实现如下:


#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(){if(!LayerColor::init()){return false;}// 初始化需要的 MenuMenu* menu = Menu::create();menu->setPosition(CCPointZero);setMenuButton(menu);//add layer touch eventauto listener = EventListenerTouchOneByOne::create();listener->setSwallowTouches(true);listener->onTouchBegan = CC_CALLBACK_2(PopupLayer::onTouchBegan, this);listener->onTouchMoved = CC_CALLBACK_2(PopupLayer::onTouchMoved, this);listener->onTouchEnded = CC_CALLBACK_2(PopupLayer::onTouchEnded, this);auto dispatcher = Director::getInstance()->getEventDispatcher();dispatcher->addEventListenerWithSceneGraphPriority(listener, this);setColor(ccc3(0,0,0));  setOpacity(128);  return true;}bool PopupLayer::onTouchBegan(Touch *touch, Event *event){return true;}void PopupLayer::onTouchMoved(Touch *touch, Event *event){}void PopupLayer::onTouchEnded(Touch* touch, Event* event){}PopupLayer* PopupLayer::create(const char* backgroundImage, Size dialogSize){PopupLayer* layer = PopupLayer::create();//layer->setSpriteBackGround(Sprite::create(backgroundImage));layer->setSprite9BackGround(Scale9Sprite::create(backgroundImage));layer->m_dialogContentSize = dialogSize;return layer;}void PopupLayer::setTitle(const char* title, int fontsize /* = 20 */){LabelTTF* label = LabelTTF::create(title,"",fontsize);setLabelTitle(label);}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(Ref* target, SEL_CallFuncN callfun){m_callbackListener = target;m_callback = callfun;    }bool PopupLayer::addButton(const char* normalImage, const char* selectedImage, const char* title, int tag /* = 0 */){auto size = Director::getInstance()->getWinSize();auto center = Point(size.width / 2, size.height / 2);// 创建图片菜单按钮auto item = MenuItemImage::create(normalImage,selectedImage,CC_CALLBACK_1(PopupLayer::buttonCallBack,this));item->setTag(tag);item->setPosition(center);// 添加文字说明并设置位置Size itemSize = item->getContentSize();LabelTTF* ttf = LabelTTF::create(title, "", 20);ttf->setColor(Color3B(0, 0, 0));ttf->setPosition(Point(itemSize.width / 2, itemSize.height / 2));item->addChild(ttf);getMenuButton()->addChild(item);return true;}void PopupLayer::buttonCallBack(Ref* pSender){Node* node = dynamic_cast<Node*>(pSender);CCLog("【====PopupLayer::buttonCallBack====】touch tag: %d", node->getTag());if (m_callback && m_callbackListener){(m_callbackListener->*m_callback)(node);}this->removeFromParent();}void PopupLayer::onEnter(){LayerColor::onEnter();Size winSize = CCDirector::getInstance()->getWinSize();Point pCenter = Point(winSize.width / 2, winSize.height / 2);//Size contentSize ;// 设定好参数,在运行时加载//如果没有设置 ContentSize ,那么采取的方案是,窗口大小与传入图片一样大// if (getContentSize().equals(this->getParent()->getContentSize())) {// getSpriteBackGround()->setPosition(ccp(winSize.width / 2, winSize.height / 2));// this->addChild(getSpriteBackGround(), 0, 0);// contentSize = getSpriteBackGround()->getTexture()->getContentSize();// } else {// Scale9Sprite *background = getSprite9BackGround();// background->setContentSize(getContentSize());// background->setPosition(ccp(winSize.width / 2, winSize.height / 2));// this->addChild(background, 0, 0);// contentSize = getContentSize();// }//添加背景图片Scale9Sprite *background = getSprite9BackGround();background->setContentSize(m_dialogContentSize);background->setPosition(Point(winSize.width / 2, winSize.height / 2));this->addChild(background,0,0);// 弹出效果Action* popupLayer = Sequence::create(ScaleTo::create(0.0, 0.0),ScaleTo::create(0.2, 1.05),ScaleTo::create(0.2, 0.95),ScaleTo::create(0.1, 1.0), CallFunc::create(CC_CALLBACK_0(PopupLayer::backgroundFinish,this)),NULL);background->runAction(popupLayer);}void PopupLayer::backgroundFinish(){Size winSize = CCDirector::getInstance()->getWinSize();Point pCenter = Point(winSize.width / 2, winSize.height / 2);// 添加按钮,并设置其位置this->addChild(getMenuButton());float btnWidth = m_dialogContentSize.width / (getMenuButton()->getChildrenCount() + 1);Vector<Node*> vector = getMenuButton()->getChildren();Ref* pObj = NULL;int i = 0;for(Node* pObj : vector){Node* node = dynamic_cast<Node*>(pObj);node->setPosition(Point( winSize.width / 2 - m_dialogContentSize.width / 2 + btnWidth * (i + 1), winSize.height / 2 - m_dialogContentSize.height / 3));i++;}// 显示对话框标题if (getLabelTitle()){getLabelTitle()->setPosition(ccpAdd(pCenter, ccp(0, m_dialogContentSize.height / 2 - 35.0f)));this->addChild(getLabelTitle());}// 显示文本内容if (getLabelContentText()){CCLabelTTF* ltf = getLabelContentText();ltf->setPosition(ccp(winSize.width / 2, winSize.height / 2));ltf->setDimensions(CCSizeMake(m_dialogContentSize.width - m_contentPadding * 2, m_dialogContentSize.height - m_contentPaddingTop));ltf->setHorizontalAlignment(kCCTextAlignmentLeft);this->addChild(ltf);}}void PopupLayer::onExit(){CCLog("popup on exit.");CCLayerColor::onExit();}


2 0