需求:用cocos2d-x开发游戏时 可能需要模态对话框 拦截下层消息
比如:购买等待模态对话框 我们点击购买按钮后不希望玩家再次点击购买 这时候我们最幸福的就是拥有一个模态对话框了
不知道咋在MAC上截图截的灰蒙蒙的...
实现原理:
模态对话框 能够拦截对话框所有下层的消息
cocos2d-x 消息处理优先级【-128,128】越小优先级越高
而菜单CCMenu kCCMenuHandlerPriority优先级 为-128
要想拦截模态对话框下层所有消息(包括菜单)
我们必须将的模态对话框优先级设置小于-128 这样就可以成功的拦截按钮的消息了
但是这样也意味着当前模态对话框的菜单消息(-128)也被拦截了
我们需要手动将消息传给模态对话框上的按钮进行处理
实现过程:
1.模态对话框派生自CCColorLayer 这样有个好处能处理触摸事件 还可以设置不透明度和背景颜色 比如半透明的灰色
setColor(ccc3(255,0,0));
setOpacity(128);
2.赋予当前模态对话框 一个接受触摸事件的最高优先级 意味着优先级数值要<-128 这样才能拦截包括按钮在内的所有消息
// 屏蔽所有priority比自己大的消息
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, kCCMenuHandlerPriority - 1, true);
3.处理触摸消息 手动将消息传送给当前模态对话框的按钮 看他们是否处理
bool DialogLayer::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
// 因为拦截了所有消息(包括按钮) 所以需要将消息手动传给模态对话框上的按钮
if (mMenu) {
mTouchedMenu = mMenu->ccTouchBegan(pTouch, pEvent);
}
return true;
}
简单的封装了一个类 还有待于改进 但目前已经能够满足使用了
#ifndef _DIALOGLAYER_H_
#define _DIALOGLAYER_H_
#include "cocos2d.h"
class DialogLayer: public cocos2d::CCLayerColor
{
public:
DialogLayer();
virtual ~DialogLayer();
public:
/** 初始化对话框 */
virtual bool onInitDialog() = 0;
/** 所有的菜单按钮压入到容器中 */
void pushMenu(cocos2d::CCMenuItem *pMenu);
virtual bool init();
virtual void onEnter();
virtual void onExit();
virtual bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
virtual void ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
virtual void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
virtual void ccTouchCancelled(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
private:
/** 初始化菜单 将菜单添加到模态对话框上*/
bool initMenu();
private:
cocos2d::CCMenu *mMenu; // 模态对话框菜单
cocos2d::CCArray *mMenuItemArray; // 所有菜单
bool mTouchedMenu; // 记录菜单点击
};
使用很简单:
1.派生一个对话框,重载实现OnInitDialog将需要的控件添加到模态对话框上
2.派生类中需要响应事件的按钮使用pushMenu添加
3.派生类实现CREATE_FUNC(class_name)宏
class ExitDlg : public DialogLayer
{
public:
virtual bool onInitDialog();
CREATE_FUNC(ExitDlg);
public:
/** 确认和退出按钮 */
void okMenuItemCallback(CCObject *obj);
void cancelMenuItemCallback(CCObject *obj);
};
bool ExitDlg::onInitDialog()
{
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
CCLabelTTF *label = CCLabelTTF::create("Are you sure exit?", "", 64);
label->setPosition(ccp(winSize.width / 2, winSize.height / 2 + 50));
this->addChild(label);
CCMenuItemFont *okMenuItem = CCMenuItemFont::create("OK", this, menu_selector(ExitDlg::okMenuItemCallback));
okMenuItem->setPosition(ccp(winSize.width / 2 - 100, winSize.height / 2 - 50));
CCMenuItemFont *cancelMenuItem = CCMenuItemFont::create("Cancel", this, menu_selector(ExitDlg::cancelMenuItemCallback));
cancelMenuItem->setPosition(ccp(winSize.width / 2 + 100, winSize.height / 2 - 50));
pushMenu(okMenuItem);
pushMenu(cancelMenuItem);
setColor(ccc3(255,0,0));
setOpacity(128);
return true;
}
void ExitDlg::okMenuItemCallback(CCObject *obj)
{
CCDirector::sharedDirector()->end();
}
void ExitDlg::cancelMenuItemCallback(CCObject *obj)
{
removeFromParentAndCleanup(true);
}
使用也相当easy
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
ExitDlg* dlg = ExitDlg::create();
addChild(dlg);
}
剩下的就是不断的重复重复再重复的利用了 哈哈
代码如下:查看代码
原理文章可以参考oneRain 的 文章 感谢作者的亲情奉献 哈哈