博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Cocos2dx引擎10-事件派发
阅读量:6836 次
发布时间:2019-06-26

本文共 12446 字,大约阅读时间需要 41 分钟。

本文介绍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::vector
mutableTouches(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 < size; ++i) { auto l =fixedPriorityListeners->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列表

转载地址:http://hkqkl.baihongyu.com/

你可能感兴趣的文章
实现HTTPS系列第五弹(终章)之【通过OpenSSL实现HTTPS】
查看>>
Linux防火墙
查看>>
如何通过一个值查找到值所在的SQL数据库表
查看>>
Python学习—面向对象学习上
查看>>
3.9 对称三位素数
查看>>
Oracle临时表空间使用分析
查看>>
傻瓜式的ARP处理方法
查看>>
Django1.4 python2.7 apache mod_python 安装与部署实例
查看>>
浅析MySql二进制日志的应用
查看>>
tcc新的插装引擎对比原有实现的改进
查看>>
layoutSubviews何时调用的问题
查看>>
Java数据类型
查看>>
[转] 配置VNC
查看>>
unity使用UGUI创建摇杆
查看>>
实习小白::(转) 使用Tui-x制作cocos能使用的界面,动画等 ---------- Tui-x 简介...
查看>>
Red Hat 6.5 网络yum源的配置
查看>>
如何解决EditText使用时,点击外侧系统键盘不消失的bug
查看>>
SWAP_JOIN_INPUTS Oracle Hint(处理hash join强制大表(segment_size大)作为被驱动表)
查看>>
使用JSP渲染Web视图
查看>>
iOS_nil、Nil、NULL、NSNull的区别
查看>>