一,总述
cocos的事件分为大概6种,分别为屏幕点击事件、键盘输入、鼠标点击、加速度事件、focus、自定义事件,对事件的操作施行的是监听机制,就是每种事件都有一个监听者类型,其中前5种监听者类型如下所示:
自定义事件需要自己继承EventListener来实现,这里不再进一步描述,下面详细详解下屏幕点击事件。
二,点击事件
点击事件可以分为两种,一种是单点触控,另一种是多点触控,实现的机制可以简单描述为监听、派发机制,即对每个事件都可以添加若干个监听者,按照优先级和渲染层级对监听者们进行排序,然后将事件依次派发给排好序的监听者们,如果其中某个监听者中断了监听(后面介绍中断的情况),则事件不再向后面的监听者派发。
多说无益,看代码!
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(Paddle::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(Paddle::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(Paddle::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
1、上面的代码执行的是添加监听者这个步骤,this指针是被监听者(可以是任一Node对象),EventListenerTouchOneByOne表明监听的是单点触控,多点触控是EventListenerTouchAllAtOnce,最后一句addEventListenerWithSceneGraphPriority是将监听者添加到事件派发管理器中,这样当你点击到被监听者时,就会触发相应的事件,该方法注册的优先级为0。
还有一个addEventListenerWithFixedPriority,这个函数的作用同样是将监听者添加到事件派发管理器中,不过他的监听对象是优先级,这个优先级是我们自己
设置的,我们可以设为除0外的任一整数。
2、下面前三个函数的作用是用来按照优先级对监听者们进行排序,最后一个是按照渲染层级的遍历监听者,具体实现可自行查阅
void sortEventListeners(const EventListener::ListenerID& listenerID);
void sortEventListenersOfSceneGraphPriority(const EventListener::ListenerID& listenerID, Node* rootNode);
void sortEventListenersOfFixedPriority(const EventListener::ListenerID& listenerID);
void visitTarget(Node* node, bool isRootNode);
3、事件派发,这是最复杂最难完全理解的步骤
按照优先级小—>大的顺序将事件依次派发给监听者,所有的监听者会依次进行touchBegan的处理,再所有监听者touchBegan处理完成后再依次进行move、end和cancle的处理。举个例子,我们有三个监听者,一个被监听者
// 被监听者
auto sprite1 = Sprite::create("HelloWorld.png");
this->addChild(sprite1);
// 监听者1,监听sprite1
auto listener1 = EventListenerTouchOneByOne::create();
listener1->setSwallowTouches(true);
listener1->onTouchBegan = [](Touch* touch, Event* event)->bool{
CCLOG("listener1 onTouchBegan");
return true;
};
listener1->onTouchMoved = [](Touch* touch, Event* event){CCLOG("listener1 onTouchMoved");};
listener1->onTouchEnded = [](Touch* touch, Event* event){CCLOG("listener1 onTouchEnded");};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);
// 监听者2,监听优先级1
auto listener2 = EventListenerTouchOneByOne::create();
listener2->setSwallowTouches(true);
listener2->onTouchBegan = [](Touch* touch, Event* event)->bool{
CCLOG("listener2 onTouchBegan");
return true;
};
listener2->onTouchMoved = [](Touch* touch, Event* event){CCLOG("listener2 onTouchMoved");};
listener2->onTouchEnded = [](Touch* touch, Event* event){CCLOG("listener2 onTouchEnded");};
_eventDispatcher->addEventListenerWithFixedPriority(listener2, 1);
// 监听者3,监听优先级-1
auto listener3 = EventListenerTouchOneByOne::create();
listener3->setSwallowTouches(true);
listener3->onTouchBegan = [](Touch* touch, Event* event)->bool{
CCLOG("listener3 onTouchBegan");
return true;
};
listener3->onTouchMoved = [](Touch* touch, Event* event){CCLOG("listener3 onTouchMoved");};
listener3->onTouchEnded = [](Touch* touch, Event* event){CCLOG("listener3 onTouchEnded");};
_eventDispatcher->addEventListenerWithFixedPriority(listener3, -1);
当事件派发时,首先listener3收到事件,因为他的优先级最低,为-1,在listener3处理事件时,首先会输出“listener3 onTouchBegan”,然后判断①是否吞掉事件和②onTouchBegan函数是否返回true,如果①和②均为是,则事件派发管理器中断事件派发,后面的listener1和listener2就接收不到事件了,但listener3的move和end会继续处理。输出如下:
如果设置吞掉事件为否,而onTouchBegan函数返回为true,则事件继续向下派发,直到事件被中断,然后再进行move、end、cancle的处理。输出如下:
如果设置吞掉事件为是,而onTouchBegan函数返回为false,则事件同样继续向下派发,与上面不同的是因为onTouchBegan函数返回为false,所以listener3的move、end、cancle不再处理。输出如下:
总结,事件是否向下派发主要受两个因素影响:是否吞掉事件、touchBegan是否返回false。
结束了,好累!orz....