在3.0版本alpha及其以后,原有的layer类的registerWithTouchDispatcher被弃置,采用全新的

EventDispatcher Mechanism

简单来说,主要包括三个部分:

1.Event Listener 封装事件监听的回调函数

2.Event Dispatcher 事件发生的时候通知Listener

3.Event Objects 携带一些相关的事件信息

就是简单的观察者模式,根据订阅情况,发出事件通知给所有的监听对象


一共有五种Event Listner

  • EventListenerTouch - responds to touch events

  • EventListenerKeyboard - responds to keyboard events

  • EventListenerAcceleration - reponds to accelerometer events

  • EventListenMouse - responds to mouse events

  • EventListenerCustom - responds to custom events

每一种对应于不同的事件。


使用方法:

1.绑定监听事件处理函数到监听对象

2.注册监听对象给事件分派机构Event Dispatcher

3.事件发生的时候,发送Event Object给所有的监听者

在新版本的API当中,可以使用C++ 11的lamda表达式的方法进行相关设置

在官方的API文档里面,有非常详细的阐释,基于的例子就是之前编译的cpp-tests

基本代码如下

	using namespace cocos2d::extension;
	bool bRet = false;
	do 
	{
		CC_BREAK_IF(!CCLayer::init());
		auto listener1 = EventListenerTouchOneByOne::create();
		listener1->setSwallowTouches(true);
		listener1->onTouchBegan = CC_CALLBACK_2(SecondScene::onTouchBegan, this);
		listener1->onTouchMoved = CC_CALLBACK_2(SecondScene::onTouchMoved, this);
		listener1->onTouchEnded = CC_CALLBACK_2(SecondScene::onTouchEnded, this);
		_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);
	//	_eventDispatcher->addEventListener(listener1);
		this->setTouchEnabled(true);#endif
		Size size = Director::sharedDirector()->getVisibleSize();
		auto sprite1 = Sprite::create("CyanSquare.png");
		sprite1->setPosition(Point(size.width / 2, size.height / 2) + Point(-80, 80));
		addChild(sprite1, 10);

		auto sprite2 = Sprite::create("MagentaSquare.png");
		sprite2->setPosition(Point(size.width/2, size.height/2));
		addChild(sprite2, 20);

		auto sprite3 = Sprite::create("YellowSquare.png");
		sprite3->setPosition(Point(0, 0));
		sprite2->addChild(sprite3, 1);   

		//Create a "one by one" touch event listener (processes one touch at a time)
		auto listener1 = EventListenerTouchOneByOne::create();
		// When "swallow touches" is true, then returning 'true' from the onTouchBegan method will "swallow" the touch event, preventing other listeners from using it.
		listener1->setSwallowTouches(true);

		// Example of using a lambda expression to implement onTouchBegan event callback function
		listener1->onTouchBegan = [](Touch* touch, Event* event){
			// event->getCurrentTarget() returns the *listener's* sceneGraphPriority node.
			auto target = static_cast<Sprite*>(event->getCurrentTarget());

			//Get the position of the current point relative to the button
			Point locationInNode = target->convertToNodeSpace(touch->getLocation());
			Size s = target->getContentSize();
			Rect rect = Rect(0, 0, s.width, s.height);

			//Check the click area
			if (rect.containsPoint(locationInNode))
			{
				log("sprite began... x = %f, y = %f", locationInNode.x, locationInNode.y);
				target->setOpacity(180);
				return true;
			}
			return false;
		};

		//Trigger when moving touch
		listener1->onTouchMoved = [](Touch* touch, Event* event){
			auto target = static_cast<Sprite*>(event->getCurrentTarget());
			//Move the position of current button sprite
			target->setPosition(target->getPosition() + touch->getDelta());
		};

		//Process the touch end event
		listener1->onTouchEnded = [=](Touch* touch, Event* event){
			auto target = static_cast<Sprite*>(event->getCurrentTarget());
			log("sprite onTouchesEnded.. ");
			target->setOpacity(255);
			//Reset zOrder and the display sequence will change
			//更改前后顺序,注释掉的话严格按照Z轴的前后顺序
			if (target == sprite2)
			{
				sprite1->setZOrder(100);
			}
			else if(target == sprite1)
			{
				sprite1->setZOrder(0);
			}
		};

		//Add listener
		_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);
		_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2);
		_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3);

	} while (0);    
	

	return true;

就是载入三个sprite图片,蓝色,红色,***,默认的顺序是,蓝色最低层,而***结点是红色结点的子结点


给三个sprite增加Touch Listner,设置swallow的flag为true

效果就是,

如果按照上述运行,不注释掉切换的那一部分code

那么

Z order的值更大的如果sprite在范围以内被点击,会吞噬掉touch事件,不会再往下一层传输


如果不采用lamda表达式方式注册事件,可以采用以往版本的

auto listener1 = EventListenerTouchOneByOne::create();
		listener1->setSwallowTouches(true);
		listener1->onTouchBegan = CC_CALLBACK_2(SecondScene::onTouchBegan, this);
		listener1->onTouchMoved = CC_CALLBACK_2(SecondScene::onTouchMoved, this);
		listener1->onTouchEnded = CC_CALLBACK_2(SecondScene::onTouchEnded, this);
		_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);