cocos2d-x 中:
关于多个层之间的点击问题
最近写了个小游戏,一个scene上有还几个层,如何只让特定的层能够响应点击,而不影响其他层呢。下面是我的解决方法。
方法一:(一般解决办法)
将需要点击的层的优先级设置为最高,将需要点击的UI空间的Rec矩形位置保持。然后在TouchEnd中判断rectcontainpoint,
以此做出对应的处理。这样就可以实现了多层中的单层点击效果。它的致命弱点就是只能以层的优先级来处理按钮的响应,而无法做到以按钮的优先级来响应按钮事件。
方法二:( 终极解决方法)
以下代码实现的功能是:按钮是按照优先级来响应的而不是以某个层来响应的(当有重合的按钮时),我想这对很多头疼于:处理多层点击透视,有了解决办法:
首先自定义一个按钮,我完全抛弃了CCMenuItem:
// // B_Button.h // HelloCpp // // Created by blary on 14-8-16. // // #ifndef __HelloCpp__B_Button__ #define __HelloCpp__B_Button__ #include <iostream> #include "cocos2d.h" using namespace cocos2d; class B_Button : public CCNode, public CCTargetedTouchDelegate { public: virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); // 参数包括 normal , selected图片, 按钮ID , 回调函数, 实现回调的代理, 位置以及优先级 bool initWithImageAndMethodAndPositionAndPriority(const char* normal, const char* selected, int n, void(*f)(int), CCNode* d, CCPoint p, int priority = kCCMenuHandlerPriority); private: CCSprite* normalS; CCSprite* selectedS; CCObject* delegate; int pid; void (*handler)(int); }; #endif /* defined(__HelloCpp__B_Button__) */
// // B_Button.cpp // HelloCpp // // Created by blary on 14-8-16. // // #include "B_Button.h" bool B_Button::initWithImageAndMethodAndPositionAndPriority(const char* normal, const char* selected, int n, void(*f)(int), CCNode* d, CCPoint p, int priority) { if (!CCNode::init()) { return false; } normalS = CCSprite::create(normal); selectedS = CCSprite::create(selected); delegate = d; pid = n; normalS->setVisible(true); selectedS->setVisible(false); addChild(normalS, 1); addChild(selectedS, 1); setContentSize(normalS->getContentSize()); setPosition(p); handler=f; CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate((CCTargetedTouchDelegate*)this, priority, true); return true; } bool B_Button::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { CCPoint p = pTouch->getLocation(); p = CCDirector::sharedDirector()->convertToUI(p); CCRect r = selectedS->boundingBox(); CCRect rect(r.origin.x + getPositionX(), r.origin.y + getPositionY(), r.size.width, r.size.height); if (rect.containsPoint(p)) { normalS->setVisible(false); selectedS->setVisible(true); return true; } else { normalS->setVisible(true); selectedS->setVisible(false); return false; } } void B_Button::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { if (normalS->isVisible()==false&&selectedS->isVisible()==true) { normalS->setVisible(false); selectedS->setVisible(true); } CCPoint p = pTouch->getLocation(); p = CCDirector::sharedDirector()->convertToUI(p); CCRect r = selectedS->boundingBox(); CCRect rect(r.origin.x + getPositionX(),r.origin.y + getPositionY(), r.size.width, r.size.height); if (rect.containsPoint(p)) { (handler)(pid); } normalS->setVisible(true); selectedS->setVisible(false); }以上就是一个自定义的按钮了:请看我的另一篇博客 http://blog.csdn.net/wanghexu09008126/article/details/39507277 中的自定义按钮,其实它们大同小异。
以下定义一个层,该层可以定义不同优先级的按钮,将按钮的相应与层完全脱离,而只保留按钮与层的包含关系。
#pragma once #include "cocos2d.h" class HelloGuyLayer : public cocos2d::CCLayer { public: virtual bool init(); CREATE_FUNC(HelloGuyLayer); }; #ifdef __cplusplus extern "C" { #endif void helloguycallback(int a); #ifdef __cplusplus } #endif
#include "HelloGuyLayer.h" #include "B_Button.h" using namespace cocos2d; // 枚举值定义 一般都是layer名称+作用 enum { GUY_LAYER_BOTTON_A, GUY_LAYER_BOTTON_B, }; #define PRIORITY_HIGH kCCMenuHandlerPriority #define PRIORITY_LOW 0 bool HelloGuyLayer::init() { if (!CCLayer::init()) { return false; } CCSize win = CCDirector::sharedDirector()->getWinSize(); // 使用自定义按钮 你可以使用默认的优先级按钮 B_Button* a = new B_Button; a->initWithImageAndMethodAndPositionAndPriority("CloseNormal.png", "CloseSelected.png", GUY_LAYER_BOTTON_A, helloguycallback, this, CCPoint(win.width/2, win.height/2),PRIORITY_LOW); a->setPosition(CCPoint(win.width/2, win.height/2)); addChild(a); a->autorelease(); B_Button* b = new B_Button; b->initWithImageAndMethodAndPositionAndPriority("CloseNormal.png", "CloseSelected.png", GUY_LAYER_BOTTON_B, helloguycallback, this,CCPoint(win.width/2 + 100, win.height/2), PRIORITY_HIGH); addChild(b); b->autorelease(); return true; } #ifdef __cplusplus extern "C" { #endif void helloguycallback(int a) { switch (a) { case GUY_LAYER_BOTTON_B: { printf(" helloguycallback B !\n"); } break; case GUY_LAYER_BOTTON_A: { printf(" helloguycallback A !\n"); } break; default: break; } } #ifdef __cplusplus } #endif以下是该如何使用了,和上面的层配合使用,在下面的代码中我使用了另一个层加上上面代码中的层来测试效果:
我将HelloGuyLayer and HelloWorld两个层同时添加到一个scene上以便测试:
#pragma once #include "cocos2d.h" class HelloWorld : public cocos2d::CCLayer { public: virtual bool init(); static cocos2d::CCScene* scene(); CREATE_FUNC(HelloWorld); }; #ifdef __cplusplus extern "C" { #endif void helloworldshutdownGame(int a); #ifdef __cplusplus } #endif
#include "HelloWorldScene.h" #include "HelloGuyLayer.h"//使用上面的层 #include "B_Button.h" using namespace cocos2d; // 枚举值定义 一般都是layer名称+作用 enum { HELLO_LAYER_BUTTON_AA, HELLO_LAYER_BUTTON_BB, }; #define PRIORITY_HIGH kCCMenuHandlerPriority #define PRIORITY_LOW 0 CCScene* HelloWorld::scene() { CCScene * scene = NULL; do { scene = CCScene::create(); HelloWorld *layer = HelloWorld::create(); HelloGuyLayer* l2 = HelloGuyLayer::create(); scene->addChild(l2); scene->addChild(layer); } while (0); return scene; } bool HelloWorld::init() { if (!CCLayer::init()) { return false; } CCSize win = CCDirector::sharedDirector()->getWinSize(); // 使用自定义按钮 你可以使用默认的优先级按钮 B_Button* aa = new B_Button; aa->initWithImageAndMethodAndPositionAndPriority("CloseNormal.png", "CloseSelected.png", HELLO_LAYER_BUTTON_AA, helloworldshutdownGame, this, CCPoint(win.width/2, win.height/2),PRIORITY_HIGH); addChild(aa); aa->autorelease(); B_Button* bb = new B_Button; bb->initWithImageAndMethodAndPositionAndPriority("CloseNormal.png", "CloseSelected.png", HELLO_LAYER_BUTTON_BB, helloworldshutdownGame, this,CCPoint(win.width/2 + 100, win.height/2), PRIORITY_LOW); addChild(bb); bb->autorelease(); return true; } #ifdef __cplusplus extern "C" { #endif void helloworldshutdownGame(int a) { switch (a) { case HELLO_LAYER_BUTTON_BB: { printf(" helloworldshutdownGame BB !\n"); } break; case HELLO_LAYER_BUTTON_AA: { printf(" helloworldshutdownGame AA !\n"); } break; default: break; } } #ifdef __cplusplus } #endif上面的测试代码中我把四个按钮分成两组:2个优先级高的和两个优先级低的,高低优先级的按钮刚好重合,点击相应的结果是只有优先级高的响应了,而不管它属于那个层。
以上测试正如所期望的那样:当按钮重合时,按钮的响应只和优先级的有关,跟层的优先级说拜拜了~~
下面的附带的文件是我测试时使用的代码。