Cocos2d-x 3.2 EventListener не работает в дочернем спрайте

Вкратце, у меня есть два спрайта, один из которых является ребенком другого. С каждым спрайтом связан прослушиватель событий, как описано там.

Если оба спрайта являются дочерними узлами слоя, то все работает отлично.

Теперь мне нужно, чтобы второй спрайт был дочерним узлом первого спрайта. Но в этом случае второй спрайт не реагирует на события вообще.

Я в панике и понятия не имею, что не так и как это исправить. Пожалуйста помоги.

Вот упрощенный пример:

.час

    #ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

class HelloWorld : public cocos2d::Layer
{
public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    // a selector callback
    void menuCloseCallback(cocos2d::Ref* pSender);

    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);
};

class PlaySprite : public cocos2d::Sprite
{
public:
    virtual bool init();

    CREATE_FUNC(PlaySprite);

    void addEvent();

    bool touchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
};

class InPlaySprite : public cocos2d::Sprite
{
public:
    virtual bool init();

    CREATE_FUNC(InPlaySprite);

    void addEvent();

    bool touchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
};

#endif // __HELLOWORLD_SCENE_H__

.cpp

    #include "HelloWorldScene.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();

    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }

    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

    // add a "close" icon to exit the progress. it's an autorelease object
    auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
                                           CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
    closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
                                origin.y + closeItem->getContentSize().height/2));
    auto menu = Menu::create(closeItem, NULL);
    menu->setPosition(Vec2::ZERO);
    this->addChild(menu, 1);

    /////////////////////////////
    // 3. add your codes below...


    auto sprite1 = PlaySprite::create();
    this->addChild(sprite1);

    auto sprite2 = InPlaySprite::create();

    // !!!
    sprite1->addChild(sprite2);

    return true;
}


void HelloWorld::menuCloseCallback(Ref* pSender)
{
    Director::getInstance()->end();
}


bool PlaySprite::init()
{
    if(!Sprite::init())
        return false;

    // to do

    Size visibleSize = Director::getInstance()->getVisibleSize();

    this->setTexture("1.png");
    this->setPosition(visibleSize.width / 2, visibleSize.height / 2);

    this->addEvent();

    return true;
}

void PlaySprite::addEvent()
{
    auto listener = EventListenerTouchOneByOne::create();

    listener->setSwallowTouches(true);

    listener->onTouchBegan = [=](Touch* touch, Event* event)
        {
            return this->touchBegan(touch, event);
        };

    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}

bool PlaySprite::touchBegan(Touch* touch, Event* event)
{
    auto target = (Sprite* ) event->getCurrentTarget();

    auto rect = this->getBoundingBox();

    if(rect.containsPoint(touch->getLocation()))
    {
        this->setTexture("1d.png");

        return true;
    }

    return false;
}


bool InPlaySprite::init()
{
    if(!Sprite::init())
        return false;

    // to do

    Size visibleSize = Director::getInstance()->getVisibleSize();

    this->setTexture("2.png");
    this->setPosition(150.0f, 150.0f);

    this->addEvent();

    return true;
}

void InPlaySprite::addEvent()
{
    auto listener = EventListenerTouchOneByOne::create();

    listener->setSwallowTouches(true);

    listener->onTouchBegan = [=](Touch* touch, Event* event)
        {
            return this->touchBegan(touch, event);
        };

    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}

bool InPlaySprite::touchBegan(Touch* touch, Event* event)
{
//  auto target = (Sprite* ) event->getCurrentTarget();

    auto rect = this->getBoundingBox();

    if(rect.containsPoint(touch->getLocation()))
    {
        this->setTexture("2d.png");

        return true;
    }

    return false;
}

Классы PlaySprite и InPlaySprite очень похожи, потому что это очень упрощенный пример.

1 ответ

Решение

Я думаю, что ваша проблема в том, что вы глотаете сенсорные события в родительском спрайте, когда вы вызываете

listener->setSwallowTouches(true);

Если вы сделаете этот звонок внутри PlaySprite::addEvent() с false вместо этого я подозреваю, что у вас все получится.

Другие вопросы по тегам