cocos2d-x 多层 触摸 已解决

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个优先级高的和两个优先级低的,高低优先级的按钮刚好重合,点击相应的结果是只有优先级高的响应了,而不管它属于那个层。

以上测试正如所期望的那样:当按钮重合时,按钮的响应只和优先级的有关,跟层的优先级说拜拜了~~

下面的附带的文件是我测试时使用的代码。





你可能感兴趣的:(游戏,UI,xcode,cocos2d-x,多层)