底层的CCMenu 穿透弹出框Touch事件 解决方法

方法有二:

一是,设置弹出层的优先级比底层的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);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值