展会信息港展会大全

Cocos2dx引擎10-事件派发
来源:互联网   发布日期:2015-09-27 15:32:43   浏览:1973次  

导读: 本文介绍Cocos2dx事件(下面简称Event)处理机制中的事件分发模块,在Event发生后,进过一系列处理,最后将会分发Event; 1、dispatchEvent& dispatch...

本文介绍Cocos2dx事件(下面简称Event)处理机制中的事件分发模块,在Event发生后,进过一系列处理,最后将会分发Event;

1、dispatchEvent& dispatchTouchEvent方法

voidEventDispatcher::dispatchEvent(Event* event)

{

if (!_isEnabled)return;

updateDirtyFlagForSceneGraph();

DispatchGuard guard(_inDispatch);

if (event->getType() ==Event::Type::TOUCH) {

dispatchTouchEvent(static_cast(event));

return;

}

auto listenerID = __getListenerID(event);

sortEventListeners(listenerID);

auto iter = _listenerMap.find(listenerID);

if (iter != _listenerMap.end()){

auto listeners = iter->second;

auto onEvent =[&event](EventListener* listener) -> bool{

event->setCurrentTarget(listener->getAssociatedNode());

listener->_onEvent(event);

return event->isStopped();

};

dispatchEventToListeners(listeners,onEvent);

}

updateListeners(event);

}

在dispatchEvent方法中:

(1)判断分发Event机制是否使能

(2)更新脏数据标志

(3)分发触摸Event

(4)分发其他类型Event

voidEventDispatcher::dispatchTouchEvent(EventTouch* event)

{

sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);

sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);

auto oneByOneListeners =getListeners(EventListenerTouchOneByOne::LISTENER_ID);

auto allAtOnceListeners =getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);

if (nullptr == oneByOneListeners &&nullptr == allAtOnceListeners)

return;

bool isNeedsMutableSet = (oneByOneListeners&& allAtOnceListeners);

const std::vector&originalTouches = event->getTouches();

std::vectormutableTouches(originalTouches.size());

std::copy(originalTouches.begin(),originalTouches.end(), mutableTouches.begin());

if (oneByOneListeners)

{

auto mutableTouchesIter =mutableTouches.begin();

auto touchesIter =originalTouches.begin();

for (; touchesIter !=originalTouches.end(); ++touchesIter) {

bool isSwallowed = false;

auto onTouchEvent =[&](EventListener* l) -> bool {....

};

dispatchEventToListeners(oneByOneListeners, onTouchEvent);

if (event->isStopped()){

return;

}

if (!isSwallowed)

++mutableTouchesIter;

}

}

if (allAtOnceListeners &&mutableTouches.size() > 0) {

auto onTouchesEvent =[&](EventListener* l) -> bool{

....

};

dispatchEventToListeners(allAtOnceListeners, onTouchesEvent);

if (event->isStopped()){

return;

}

}

updateListeners(event);

}

在dispatchTouchEvent方法中:

(1) 对单指点击&多指点击EventListener列表进行排序;当然排序算法中首先判断目前EventListener列表是否为脏数据,如果是脏数据,则进行排序;排序的具体细节下面会详细讲述

(2) 获取单指点击&多指点击EventListener列表,并判断EventListener是否为空

(3) 获取Event信息

(4) 若单指点击EventListener列表不为空,则分发单指点击Event

(5) 若多指点击EventListener列表不为空,则分发多指点击Event

(6) 更新EventListener列表状态

2、dispatchTouchEvent 方法中EvnetListener排序sortEventListeners

在dispatchTouchEvent方法中使用了sortEventListeners方法对EventListener列表进行排序,下面将详细讲解该方法;

voidEventDispatcher::sortEventListeners(const EventListener::ListenerID&listenerID) {

DirtyFlag dirtyFlag = DirtyFlag::NONE;

auto dirtyIter =_priorityDirtyFlagMap.find(listenerID);

if (dirtyIter !=_priorityDirtyFlagMap.end()){

dirtyFlag = dirtyIter->second;

}

if (dirtyFlag != DirtyFlag::NONE) {

dirtyIter->second = DirtyFlag::NONE;

if ((int)dirtyFlag &(int)DirtyFlag::FIXED_PRIORITY) {

sortEventListenersOfFixedPriority(listenerID);

}

if ((int)dirtyFlag &(int)DirtyFlag::SCENE_GRAPH_PRIORITY) {

auto rootNode =Director::getInstance()->getRunningScene();

if (rootNode) {

sortEventListenersOfSceneGraphPriority(listenerID, rootNode);

}else{

dirtyIter->second =DirtyFlag::SCENE_GRAPH_PRIORITY;

}

}

}

}

在sortEventListeners方法中:

(1)在脏数据列表中查找该listenerID的EventListener是否存在脏数据,若不存在脏数据则不需要排序,退出该方法;若存在脏数据,则进行排序

(2)针对优先级不等于0的EventListener列表进行排序

(3)针对优先级等于0的EventListener列表进行排序

下面为优先级不等于0的EventListener列表排序方法:

voidEventDispatcher::sortEventListenersOfFixedPriority(constEventListener::ListenerID& listenerID) {

auto listeners = getListeners(listenerID);

if (listeners == nullptr) return;

auto fixedListeners =listeners->getFixedPriorityListeners();

if (fixedListeners == nullptr) return;

std::sort(fixedListeners->begin(),fixedListeners->end(), [](const EventListener* l1, const EventListener* l2){

return l1->getFixedPriority() getFixedPriority();

});

intindex = 0;

for (auto& listener : *fixedListeners){

if (listener->getFixedPriority()>= 0)

break;

++index;

}

listeners->setGt0Index(index);

}

在sortEventListenersOfFixedPriority方法中:

(1) 根据ID获取EventListener列表,并判断列表是否为空

(2) 获取EventListener列表中优先级不等于0的EventListener列表_fixedListeners

(3) 使用STL中sort方法对_fixedListeners方法从小到大排序

(4) 统计fixedListeners类表中优先级数值小于0的EventListener的个数

从排序的方法可以得知,高优先级(数值越小优先级越高)EventListener先执行;若优先级相同,先注册的EventListener先执行

下面为优先级等于0的EventListener列表排序方法:

voidEventDispatcher::sortEventListenersOfSceneGraphPriority(constEventListener::ListenerID& listenerID, Node* rootNode) {

auto listeners = getListeners(listenerID);

if (listeners == nullptr)return;

auto sceneGraphListeners =listeners->getSceneGraphPriorityListeners();

if (sceneGraphListeners == nullptr)return;

_nodePriorityIndex = 0;

_nodePriorityMap.clear();

visitTarget(rootNode, true);

std::sort(sceneGraphListeners->begin(),sceneGraphListeners->end(), [this](const EventListener* l1, constEventListener* l2) {

return_nodePriorityMap[l1->getAssociatedNode()] > _nodePriorityMap[l2->getAssociatedNode()];

});

}

在sortEventListenersOfSceneGraphPriority方法中:

(1) 根据ID获取EventListener列表,并判断列表是否为空

(2) 获取EventListener列表中优先级等于0的EventListener列表_sceneGraphListeners

(3) 使用_globalZOrder值对该Scene下的Node排序

(4) 根据EventListener对应Node的_globalZOrder值从大到小将_sceneGraphListeners列表排序

3、dispatchTouchEvent 方法中dispatchEventToListeners方法

voidEventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, conststd::function& onEvent) {

bool shouldStopPropagation = false;

auto fixedPriorityListeners =listeners->getFixedPriorityListeners();

auto sceneGraphPriorityListeners =listeners->getSceneGraphPriorityListeners();

ssize_t i = 0;

if (fixedPriorityListeners) {

if(!fixedPriorityListeners->empty()){

for (; i getGt0Index(); ++i) {

auto l =fixedPriorityListeners->at(i);

if (l->isEnabled()&& !l->isPaused() && l->isRegistered() &&onEvent(l)) {

shouldStopPropagation =true;

break;

}

}

}

}

if (sceneGraphPriorityListeners) {

if (!shouldStopPropagation) {

for (auto& l :*sceneGraphPriorityListeners) {

if (l->isEnabled()&& !l->isPaused() && l->isRegistered() &&onEvent(l)) {

shouldStopPropagation =true;

break;

}

}

}

}

if (fixedPriorityListeners) {

if (!shouldStopPropagation) {

ssize_t size =fixedPriorityListeners->size();

for (; i at(i);

if (l->isEnabled()&& !l->isPaused() && l->isRegistered() &&onEvent(l)) {

shouldStopPropagation = true;

break;

}

}

}

}

}

在dispatchEventToListeners函数中:

(1) 获取_fixedListeners&_sceneGraphListeners列表

(2) 当_fixedListeners不为空时;执行_fixedListeners类表中EventToListener处理

(3) 当_sceneGraphListeners不为空时;执行_sceneGraphListeners类表中EventToListener处理

在_fixedListeners类表中EventToListener处理中,优先级小于0的是不执行的处理方法的;EventToListener的处理方法是通过参数传递过来的匿名函数;该匿名函数的实现下面会继续讲述

4、dispatchTouchEvent 方法中单点匿名方法onTouchEvent

auto onTouchEvent =[&](EventListener* l) -> bool {

EventListenerTouchOneByOne* listener =static_cast(l);

if (!listener->_isRegistered) returnfalse;

event->setCurrentTarget(listener->_node);

bool isClaimed = false;

std::vector::iteratorremovedIter;

EventTouch::EventCode eventCode =event->getEventCode();

if (eventCode ==EventTouch::EventCode::BEGAN){

if (listener->onTouchBegan){

isClaimed =listener->onTouchBegan(*touchesIter, event);

if (isClaimed &&listener->_isRegistered){

listener->_claimedTouches.push_back(*touchesIter);

}

}

}

else if (listener->_claimedTouches.size()> 0

&& ((removedIter =std::find(listener->_claimedTouches.begin(),listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end())){

isClaimed = true;

switch (eventCode) {

case EventTouch::EventCode::MOVED:

if (listener->onTouchMoved) {

listener->onTouchMoved(*touchesIter,event);

}

break;

case EventTouch::EventCode::ENDED:

if (listener->onTouchEnded) {

listener->onTouchEnded(*touchesIter,event);

}

if (listener->_isRegistered) {

listener->_claimedTouches.erase(removedIter);

}

break;

caseEventTouch::EventCode::CANCELLED:

if (listener->onTouchCancelled){

listener->onTouchCancelled(*touchesIter,event);

}

if (listener->_isRegistered) {

listener->_claimedTouches.erase(removedIter);

}

break;

default:

CCASSERT(false, "Theeventcode is invalid.");

break;

}

}

if (event->isStopped()){

updateListeners(event);

return true;

}

if (isClaimed &&listener->_isRegistered && listener->_needSwallow) {

if (isNeedsMutableSet){

mutableTouchesIter =mutableTouches.erase(mutableTouchesIter);

isSwallowed = true;

}

return true;

}

return false;

};

在匿名方法onTouchEvent中:

(1) 将传递参数强制转换成EventListenerTouchOneByOne类型,并判断是否为空

(2) 获取触摸(Win32下为鼠标点击\拖动)Event类型

(3) 判断Event类型是BEGAN时

a)调用EventListener在注册时指定的onTouchBegan,并获取返回值

b)若返回值是true,将该Event的Touch信息放入_claimedTouches中

(4) 判断Event类型不是BEGAN时

a)_claimedTouches的内容不为空,在_claimedTouches中有该Event的Touch信息

b)若Event类型是MOVED,调用EventListener在注册时指定的onTouchMoved

c)若Event类型是ENDED,调用EventListener在注册时指定的onTouchEnded

d)若Event类型是CANCELLED,调用EventListener在注册时指定的onTouchCancelled

e)将该Event的Touch信息从_claimedTouches中移除

(5) 若该Event被停止,更新EventListener列表

(6) 若在onTouchBegan返回值为true,并且_needSwallow被设置为true时,将当前Event从多点触摸Event列表中移除

在该匿名方法中,onTouchBegan的返回值很重要,他关注着后续其他触摸操作(onTouchMoved\onTouchEnded\onTouchCancelled)是否执行,关注则_needSwallow标志是否生效;

5、dispatchTouchEvent 方法中多点的匿名方法onTouchEvent

auto onTouchesEvent= [&](EventListener* l) -> bool{

EventListenerTouchAllAtOnce* listener =static_cast(l);

if (!listener->_isRegistered) returnfalse;

event->setCurrentTarget(listener->_node);

switch (event->getEventCode())

{

case EventTouch::EventCode::BEGAN:

if (listener->onTouchesBegan) {

listener->onTouchesBegan(mutableTouches,event);

}

break;

case EventTouch::EventCode::MOVED:

if (listener->onTouchesMoved) {

listener->onTouchesMoved(mutableTouches,event);

}

break;

case EventTouch::EventCode::ENDED:

if (listener->onTouchesEnded) {

listener->onTouchesEnded(mutableTouches,event);

}

break;

case EventTouch::EventCode::CANCELLED:

if (listener->onTouchesCancelled){

listener->onTouchesCancelled(mutableTouches,event);

}

break;

default:

CCASSERT(false, "The eventcodeis invalid.");

break;

}

if (event->isStopped()){

updateListeners(event);

return true;

}

return false;

};

在匿名方法onTouchEvent中:

(1)将传递参数强制转换成EventListenerTouchAllAtOnce类型,并判断是否为空

(2)获取触摸(Win32下为鼠标点击\拖动)Event类型

(3)若Event类型为BEGAN时,调用EventListener在注册时指定的onTouchBegan方法

(4)若Event类型为MOVED时,调用EventListener在注册时指定的onTouchesMoved方法

(5)若Event类型为ENDED时,调用EventListener在注册时指定的onTouchesEnded方法

(6)若Event类型为CANCELLED时,调用EventListener在注册时指定的onTouchesCancelled方法

(7)若该Event被停止,更新EventListener列表

赞助本站

人工智能实验室
AiLab云推荐
推荐内容
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港