EventListener doesn't swallow

Hi,

I’m using latest develop branch of Cocos2d-x. I have an object, when I create it I create a listener like this:

listener = EventListenerTouchOneByOne::create(); listener->setSwallowTouches(true); listener->onTouchBegan = CC_CALLBACK_2(MyObject::onTouch, listener); Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);

It works as expected and events get swallowed correctly, but when I add the following lines to my onTouch method swallowing is ignored:

Director::getInstance()->getEventDispatcher()->removeEventListener(listener); getParent()->removeChild(sender);

Any ideas why this is happening. Is this a bug or should I only mark the object to be removed later (this will indeed fix my issue)?

I’m not really sure about this… but once you remove the EventListener… are you still expecting the events to be passed to the object? Maybe I’m too naive here but I would say you need the Listener as long as you want events triggering your callbacks.

Each object creates its own independent listener. When two objects are at the same position I only want to receive the top object to receive the touch. So I return true in my onTouchCallback to stop the propagation of the events to the underlaying objects. This works fine. But when remove it from the scene, then returning true the propagation isn’t stopped.

I’ve fixed it in my project by delaying this to a later time, but I’ve wondered if this behaviour is expected or this is a bug.

What’s sender ?
If you remove the listener, the callback of it will not be invoked certainly.
Could you paste more codes for that? I will be glad to help you find out the problem. :slight_smile:

But when remove it from the scene, then returning true the propagation isn’t stopped.

If it was removed from scene, it will not get response. If it did get response, I think it’s a bug.

Please upload a demo to reproduce this issue. I will check that. :slight_smile:

Sorry to wake up this thread, but the issue still exists:

If you have a node that is touched and swallows the touch (onTouchBegan return true), but the in onTouchBegan this node also gets removed, the touch will not be swallowed.

It is not swallowed since in OnExit the event handlers registered-flag is set to false. If the registered-flag is set to false, no touches will be swallowed any longer.

I think it is wrong behaviour that a touch of a no longer existing node is not swallowed, even if you explicitely return true.

bool MyNode::onTouchBegan(Touch *touch, Event *event)
{

    removeFromParent();
    return true;
}

@framusrock @slackmoehrle hello sir, I am having the same problem, Did you find the solution?

This hasn’t been an issue in years. Please share your code and cocos version details, platform, etc.

@slackmoehrle @dumganhar @joemanaco @Byfron @framusrock sorry for late response, this is the function we have implemented for reproduce the bug

void HelloWorld::demoFun(){

    auto frameSize = Director::getInstance()->getVisibleSize();

    int layerCreated = 0;
    int layerRemoveFromParen = 0;

    auto layerCreatedLbl = Label::createWithTTF(StringUtils::format("Layer created : %d", 0), "Helvetica.ttf", frameSize.width * 0.1f);
    layerCreatedLbl->setPosition(Vec2(frameSize.width * 0.5f, frameSize.height * 0.9f));
    this->addChild(layerCreatedLbl);

    auto layerRemoveddLbl = Label::createWithTTF(StringUtils::format("Layer removed : %d", 0), "Helvetica.ttf", frameSize.width * 0.1f);
    layerRemoveddLbl->setPosition(Vec2(frameSize.width * 0.5f, frameSize.height * 0.85f));
    this->addChild(layerRemoveddLbl);


    auto mainButton = ui::Button::create();
    mainButton->setContentSize(Size(frameSize.width , frameSize.width * 0.3f));
    mainButton->setScale9Enabled(true);
    mainButton->setCascadeColorEnabled(true);
    mainButton->setColor(Color3B::YELLOW);
    mainButton->setPosition(Vec2(frameSize.width * 0.5f, frameSize.height * 0.7f));
    mainButton->setTitleText("Click Me Button");
    mainButton->setTitleFontSize(mainButton->getContentSize().height * 0.4f);
    this->addChild(mainButton, 0);

    mainButton->addClickEventListener([&, mainButton, frameSize, layerCreatedLbl, layerRemoveddLbl, layerCreated, layerRemoveFromParen](Ref * ref) mutable {

        mainButton->setColor(Color3B::BLACK);
        layerCreatedLbl->setString(StringUtils::format("Layer created : %d", layerCreated++));

        auto layer = cocos2d::LayerColor::create(Color4B(53, 53, 53, 200));
        layer->setAnchorPoint(Point::ANCHOR_MIDDLE);
        layer->setContentSize(frameSize);
        layer->setColor(Color3B::GREEN);
        this->addChild(layer, 1);

        auto listener = EventListenerTouchOneByOne::create();
        listener->setSwallowTouches(true);

        listener->onTouchBegan = [&, layer, mainButton, listener, layerRemoveddLbl, layerRemoveFromParen](Touch *touch, Event *event) mutable {

            if (layer) {

                if (layer->getBoundingBox().containsPoint(layer->convertToNodeSpace(touch->getLocation()))) {

                    layerRemoveddLbl->setString(StringUtils::format("Layer removed : %d", layerRemoveFromParen++));
                    _eventDispatcher->removeEventListener(listener);
                    mainButton->setColor(Color3B::YELLOW);
                    layer->removeFromParentAndCleanup(true);

                }

            }

            return true;
        };

        _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, layer);

        auto layerText = Label::createWithTTF("Click Me Layer", "Helvetica.ttf", frameSize.width * 0.1f);
        layerText->setCascadeOpacityEnabled(false);
        layerText->setPosition(layer->getContentSize()/2);
        layer->addChild(layerText);


    });



}

So what is the end goal you are hoping for?

@slackmoehrle thanks for reply, what happening here is, when we click on button it creates one layer top of the button, now we have set listener as you can see in code, so when we touch layer and if we touched inbound layer it should remove from parent and that’s what happens, but now the problem is when I click on layer just above the button it’s detecting touch for layer and so it is removing layer too, but that touch is passing to button also and this touch happened in button boundary, so it creates new layer immediately but when we touch somewhere else on layer it just remove, so I guess this comment is explaining the problem

we are not sure this is the bug or not but what we think is that once layer detects touch is removed from parent and touch should not pass to button and so button click should not trigger, we are having this problem cause we have to implement Shop in-game and when player click item from the list one popup show off and that popup doesn’t cover the whole screen so we show off layer with opacity as in demo fun and so when player click on that opacity layer, current popup removed but same time below item (button) trigger and opens up new popup

ok, I see. Let’s see what we can find

1 Like

one thing I notice is that you always return true; but I guess that could be appropriate for your needs. It does signal that the touch should be consumed.

I was looking at some of my games and I think we are close in how we deal with touch events

// touch events.
    auto listener = cocos2d::EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(true);
    
    listener->onTouchBegan = [&](cocos2d::Touch* touch, cocos2d::Event* event)
    {
        if (!_gameObject->Instance()->getGameIsPaused())
        {
            cocos2d::Vec2 p = touch->getLocation();
            cocos2d::Rect rect = this->getBoundingBox();
            
            if(rect.containsPoint(p))
            {
                CornSprite::touchEvent(touch);
                return true;
            }
        }
        
        return false;
    };
    
    listener->onTouchEnded = [=](cocos2d::Touch* touch, cocos2d::Event* event)
    {
    };
    
    cocos2d::Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
1 Like

or you could use

event->stopPropogation();

This works for all events not just touches.

2 Likes

thanks all, Yeah this is working :slight_smile:

1 Like

This is actually the best answer.

2 Likes

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.