方法有二:
一是,设置弹出层的优先级比底层的CCMenu还要高,如-129;
二是,自定义CCMenu类。
方法一Demo:
在游戏中,通常会需要有弹出提示框,在中途弹出这些操作的时候,由于scene没有隐藏,所以scene上面的menu是可以接收到上层传递下来的消息的,为了避免menu接收消息,可以创建一个自己的layer类,并继承于cclayer,使这个layer的优先级提高并吞噬所有会向下传递的事件,然后在这个layer中完成自己需要的功能。
下面这个例子演示的是在当前scene中点击一个按钮的时候,弹出自定义的layer,并且播放一段动作,播放中途,点击这层layer是不会关闭的,点击的事件也不会传递到下面的scene上,当动作执行完毕后,再点击这个layer,就会退出返回到scene界面。可以根据自己的需要,在这个layer上面加ccmenu。
//
// DialogMessage.h
// MyTest
//
// Created by armyshen on 13-7-22.
//
//
#include "cocos2d.h"
#ifndef MyTest_DialogMessage_h
#define MyTest_DialogMessage_h
USING_NS_CC;
class DialogMessage: public CCLayerColor
{
public:
~DialogMessage();
static DialogMessage* sharedDialogMessage(void);
void initDialog();
virtual bool init();
void onEnter();
void onExit();
void actionCallBack();
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
private:
//构造函数私有化,是为了避免外部创建对象,这个类一般是共有的,所以做成一个单例的形式
DialogMessage();
bool m_bPlayAchieve;//播放是否完成
};
#endif
//
// DialogMessage.cpp
// MyTest
//
// Created by armyshen on 13-7-22.
//
//
#include "DialogMessage.h"
static DialogMessage *g_Instant = NULL;
//创建单例,要使用这个类,必须使用这个接口获得实例对象
DialogMessage* DialogMessage::sharedDialogMessage(void)
{
if(!g_Instant)
{
g_Instant = new DialogMessage();
g_Instant->init();
}
return g_Instant;
}
DialogMessage::DialogMessage()
{
}
DialogMessage::~DialogMessage()
{
}
void DialogMessage::initDialog()
{
//初始化layer的颜色为灰色,给人下面scene变灰的感觉
this->setColor(ccGRAY);
//透明度
this->setOpacity(150);
m_bPlayAchieve = false;
//在当前的layer上添加一个sprite,并做缩放和旋转动作
CCSize size = CCDirector::sharedDirector()->getWinSize();
CCSprite *pIcon = CCSprite::create("Icon@2x.png");
pIcon->setPosition(ccp(size.width / 2, size.height / 2));
pIcon->setScale(0.25);
pIcon->setRotation(180);
this->addChild(pIcon,0);
CCActionInterval *action1 = CCScaleBy::create(3, 4);
CCActionInterval *action2 = CCRotateTo::create(3, 360);
CCFiniteTimeAction *action3 = CCCallFunc::create(this, callfunc_selector(DialogMessage::actionCallBack));
pIcon->runAction(CCSequence::create(action1, action2, action3, NULL));
}
//动作播放完毕之后,把标志位置为true
void DialogMessage::actionCallBack()
{
m_bPlayAchieve = true;
}
bool DialogMessage::init()
{
if ( !CCLayerColor::init() )
{
return false;
}
return true;
}
//进入这个layer的时候,设置它的优先级比ccmenu高,并且吞噬消息,这样消息就不会向下传递了
void DialogMessage::onEnter()
{
CCLayerColor::onEnter();
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -129, true);
initDialog();
}
//退出layer的时候,移除touch事件代理
void DialogMessage::onExit()
{
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
removeAllChildren();
}
bool DialogMessage::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
return true;
}
void DialogMessage::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
}
//当动画播放完毕,点击这个layer之后,就会将自己从scene中删除,可以放在其他事件中处理,看具体需求
void DialogMessage::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
if(m_bPlayAchieve)
{
removeFromParent();
}
}
void DialogMessage::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent)
{
}
//在cocos2d-x生成的例子中,添加自己创建的layer
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
DialogMessage *dMsg = DialogMessage::sharedDialogMessage();
this->addChild(dMsg);
}
当然,这样后,因为本层优先级太高,会出现问题:即不能响应本层的控件的触摸事件。解决方法如下:
当自定义一个CCLayer并且设置了吞噬消息之后,比如:
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -129, true);
设置了上述代码之后,当前Layer上面的触摸事件将不会被传递到其他层上,当前Layer上的CCMenu也将无法接收到点击事件。这似乎有些违背我们的初衷,本来是想屏蔽其他层的事件接收,但谁晓得当前Layer的CCMenu也无法接收点击事件了~囧
解决办法:在进入当前Layer的时候,在onEnter函数中重新设置CCMenu的优先级
void TestLayer::onEnter()
{
CCLayerColor::onEnter();
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -129, true);
if(pMenu->isRunning())
{
CCTouchDispatcher *pTouchDispatcher=CCDirector::sharedDirector()->getTouchDispatcher();
pTouchDispatcher->removeDelegate(pMenu);
pTouchDispatcher->addTargetedDelegate(pMenu,-130,true);
}
}
pMenu就是当前Layer上的一个按钮,按照上面的方法设置之后,就可以既屏蔽其他Layer接收触摸或者点击事件,又能相应当前Layer上的CCMenu了
---------------------------------------------------------------------------------------------------
方法二Demo:
#pragma once
// MyMenu
#include "cocos2d.h"
using namespace cocos2d;
class MyMenu : public CCMenu
{
public:
MyMenu(void);
~MyMenu(void);
/** creates a CCMenu with it's items */
static MyMenu* create(CCMenuItem* item, ...);
// 重写registerWithTouchDispatcher
virtual void registerWithTouchDispatcher();
};
#include "MyMenu.h" MyMenu::MyMenu(void) { } MyMenu::~MyMenu(void) { } MyMenu * MyMenu::create(CCMenuItem* item, ...) { va_list args; va_start(args,item); MyMenu *pRet = new MyMenu(); if (pRet && pRet->initWithItems(item, args)) //适合2.0.4等老版本 ---(2.1.4版本 pRet->createWithItems(item, args);)
{ pRet->autorelease(); va_end(args); return pRet; } va_end(args); CC_SAFE_DELETE(pRet); return NULL; } // 重写registerWithTouchDispatcher void MyMenu::registerWithTouchDispatcher() { //这里优先级设为1,只要比CCScrollView、tableView、CCControlButton等(这些优先级都为0)低就可以 CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 1, true); }