EventListener in child node v3.2 - I am desperate

Hi!

Briefly, I have two sprites, one of which is a child of another.
With each sprite related the event listener, as described there.

If both sprites are child nodes of the layer, then everything works great.

Now I need to second sprite is a child node of the first sprite.
But in this case, the second sprite does not respond to events in general.

I’m in a panic and have no idea what’s wrong and how to fix it. Please help.

Here’s a simplified example:

	#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__

and cpp file

	#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;
}

It’s cause you are setting listener->setSwallowTouches(true);
If set, it swallows the events when you return true in the listener. Set to false and it will propagate it to the child…

1 Like

good catch @IQD that call is deprecated at this point I think too.

1 Like

Or leave it to true and return false in the parent and return true in the child.

Does work in both ways.

1 Like

I’m sorry for the late entry, my computer was unavailable due to a fault of the hard drive. I am only now able to restore the data.

Thank you for your help !! It really solved the problem!))

Once again, thank you very much)