[Resolved] Passing the touch & event to the underlying node

Hello everyone,

I have currently started to develop a game in C++ and while managing the touch events I have run into the following challenge.

Inside the method “onTouchBegan” I am checking if the hunter that is shooting is not idle (Recharging arrow) to pass the touch event to the parent Layer of the GameScene, so the OnTouchMoved and OnTouchEnded events don’t get executed.

The code that I have wrote is something like this:

bool GameScene::onTouchBegan( Touch* touch, Event* event )
{
// Ignore all touches if we are not on Idle mode
if ( this->_hunter->hunterState != HunterStateIdle )
{
Layer::onTouchBegan( touch, event);
return;
}

// Obtain the coordinates where the touch was done
Point touchLocation = touch->getLocation( );
// Make hunter aim to the point touched
_hunter->aimAtPoint( touchLocation );
return true;

}

The problem that I have is mainly with the function:

Layer::onTouchBegan( touch, event);

I know in Objective C would be something like:

[super touchBegan:touch withEvent:event];

Any ideas about what I am doing wrong?

Thanks in advance.

What kind of touch event listener do you choose? Scene graph or fixed priority?

If you choose scene graph listener type, you could set swallowTouch to false and simply return false in onTouchBeban method to pass the touch event to the underlying node.

It does not have to be set to false. It can also be set to true and just return false.

From some example code: http://www.cocos2d-x.org/docs/manual/framework/html5/v3/eventManager/en

// When “swallow touches” is true, then returning ‘true’ from the onTouchBegan method will “swallow” the touch event, preventing other listeners from using it.

If set to false, it will never swallow it anyway, cause isClaimed will be false and the code will bale out before even checking _needSwallow(regardless of what swallowTouch sets it to).

From CCEventDispatcher.cpp

if (eventCode == EventTouch::EventCode::BEGAN)
{
    if (listener->onTouchBegan)
    {
        isClaimed = listener->onTouchBegan(*touchesIter, event);
        if (isClaimed && listener->_isRegistered)
        {
            listener->_claimedTouches.push_back(*touchesIter);
        }
    }
}
if (isClaimed && listener->_isRegistered && listener->_needSwallow)
{
    if (isNeedsMutableSet)
    {
        mutableTouchesIter = mutableTouches.erase(mutableTouchesIter);
        isSwallowed = true;
    }
    return true;
}
                
return false;

Thank you guys. The article was very useful, bookmarked :wink:

I fixed it returning false :smiley:

// Ignore all touches if we are not on the Idle mode
if ( this->_hunter->hunterState != HunterStateIdle )
{
return false;
}

So if I understand correctly, when setSwallowTouch is set to True. If top A is on top of node B and they are touched, only top A will receive the event. However, if set to false, both of them will receive right?

Also, could you please explain me for what it is used the return value of onTouchBegan?

Thanks in advance.

Yes, setting setSwallowTouch to true, just enables you with the option to swallow/not swallow the touch, based on the return type of true/false. If you set setSwallowTouch to false, the return type is a `don’t care’. None of the nodes will swallow it, and it will be delegated to all other nodes, which are a parent of the node, that originally received the touch.

E.g. Sprite is a child on a layer: the sprite receives the originally touch. As the layer is a parent of the sprite node, it will also receive the touch.

If setSwallowTouch is set to true and you return true(and only then!), the touch on the sprite node will be consumed by it and the touch will not be delegated to the layer.

The return type tells the event dispatcher, if the touch should be swallowed by the node and not being delegated to the parent nodes. If you return false in onTouchBegan(or any other event callback), it will not be swallowed and be delegated. If you return true in onTouchBegan(or any other event callback), it will be swallowed by the node and not being delegated.
Never the less this behavior will only work, if you set it to true in setSwallowTouch. Here true means “enable that feature”.

2 Likes

Thanks a lot, everyting is more clear now :wink:

I encountered some unexpected touch behavior and dug around to try to figure it out. I discovered a few things not covered in the new events documentation (http://cocos2d-x.org/programmersguide/ch8.html)

  1. When a listener does not consume a touch in its onTouchBegan method, yet the onTouchBegan method returns true, that listener has claimed the touch and the listener’s secondary methods will run (onTouchMoved/onTouchEnded). Other listeners may also return true from their onTouchBegan method to claim the touch and run their secondary methods. If a listener returns false from the onTouchBegan method, its secondary methods will not run. For test results that reveal the impact of this see test scenarios below.

  2. The stopPropagation method can be called in any listener method to stop the event from propagating to other listeners. If stopPropagation is called in onTouchBegan, the listener’s secondary listener methods are still run if the method returns true (e.g., stopPropagation only stops other listeners from executing, it doesn’t prevent the secondary methods in the same listener from executing). Event swallowing may only be performed in the onTouchBegan method, but stopPropagation may be performed from any listener method.

  3. If you want to execute secondary touch listener methods (onTouchMoved/onTouchEnded) but not onTouchBegan, you must configure an onTouchBegan method even if it doesn’t do anything but return true. onTouchBegan must run and claim the touch in order to trigger the secondary touch listener methods.

Tests:
2 sprites placed on the stage. A listener is created with an onTouchBegan and onTouchEnded method. It is applied to the first sprite and cloned and applied to the other. Two things are modified, creating 4 scenarios: The setSwallowTouches method is tested with true/false settings and the onTouchBegan method is tested with return values of true/false.

a) configuration:
— setSwallowTouches( true )
— onTouchBegan returns true

results:
Sprite 1 gets onTouchBegan and onTouchEnded. Sprite 2 gets neither.

eval:
This is as expected, setSwallowTouches( true ) grants permission to swallow touches and onTouchBegan’s return type of true requests the swallow.

b) configuration:
— setSwallowTouches( true )
— onTouchBegan returns false

results:
Sprite 1 gets onTouchBegan but not onTouchEnded. Sprite 2 also gets onTouchBegan but not onTouchEnded.

eval:
This was unexpected before I understood the touch claiming process. setSwallowTouches( true ) grants permission to swallow touches, but neither sprite’s onTouchBegan method returns true to request the swallow, so the event is not swallowed. So it was unexpected when both Sprites did not execute their onTouchEnded method since the event was not swallowed. The reason is that each listener’s onTouchBegan method returns false, not claiming the touch, so therefore they don’t execute any of the secondary listener methods.

c) configuration:
— setSwallowTouches( false )
— onTouchBegan returns true

results:
Sprite 1 gets onTouchBegan and onTouchEnded. Sprite 2 also gets onTouchBegan and onTouchEnded.

eval:
Because setSwallowTouches is set to false, it’s expected that the touch will not be swallowed, therefore multiple listeners will respond to the touch. The listeners return true from their onTouchBegan methods, so secondary methods (onTouchEnded) run.

d) configuration:
— setSwallowTouches( false )
— onTouchBegan returns false

results:
Sprite 1 gets onTouchBegan but not onTouchEnded. Sprite 2 is the same, it gets onTouchBegan but not onTouchEnded.

eval:
Similar to test c, because setSwallowTouches is set to false, it’s expected that the touch will not be swallowed, therefore multiple listeners will respond to the touch. However in this case the onTouchBegan methods return false so their secondary touch listener methods do not run (onTouchEnded).

@EMebane Thanks for posting this. I’ll take a look at what you are saying and see what needs to be worked on in chapter 8.