源代码版本号来自3.x,转载请注明

cocos2d-x 源代码分析总文件夹

http://blog.csdn.net/u011225840/article/details/31743129

1.继承结构

1.1 结构

      不详吐槽太多,也不贴图了。贴图要审核好久好久好久好久。
      从小到大,先来看下Event的结构。
      1.Event--------EventTouch,EventCustom,EventMouse,EventKeyboard,EventFocus,EventAcceleration
       当中,EventTouch 和 EventCustom是比較特殊的两个Event。EventTouch是3.x版本号的触摸机制相关的Event,而EventCustom则是3.x自己定义事件机制的基础。该机制代替了2.x版本号中的NotificationCenter。

      2.EventListener-------------EventListenerTouchOneByOne,EventListenerTouchAllAtOnce,EventListenerCustom,EventListenerFocus。EventListenerMouse....相应
      相比于Event,Listener多了一个,由于相应的Touch被拆分成了两个Listener。一个是OneByone,一个是TouchAllAtOnce。前者是onTouchBegan等函数的Listener,后者是onTouchesBegan等函数的Listener。



1.2.EventDispatcher,EventListener,Event三者的关系

       Event相当于data,EventListener包括了data与fuction的一种映射关系,而EventDispatcher相当于一个Manager,管理着EventListener,决定着Event的调用顺序。
       Event中包括了type。target等信息;EventListener包括了ListenerID。相关联的Node。相应的callBack;EventDispatcher里含有各种map,vector来管理不同的Listener。

详细的,能够看源代码分析。


2.源代码分析

        本次源代码分析的量比較大,大家要有心理准备哟~

2.1Event相关

2.1.1 Event


 enum class Type
{
TOUCH,
KEYBOARD,
ACCELERATION,
MOUSE,
FOCUS,
CUSTOM
};
Type _type; ///< Event type bool _isStopped; ///< whether the event has been stopped.
Node* _currentTarget;
      Event主要包括了三个重要的变量,type,是一个enum变量,里面定义了类型。isStopped定义该event是否已经停止。当一个event发生停止时。与其相关的Listener都要停止callback的调用;currentTarget是与该Event相关联的node。


2.1.2 EventTouch

    EventTouch是cocos2d-x引擎中很很重要的事件。相应于四种touch操作。该类内部定义了四种EventCode
    
 enum class EventCode
{
BEGAN,
MOVED,
ENDED,
CANCELLED
};

      不同的EventCode能够告诉Listener来调用不同的callback。

       除此之外,EventTouch中含有std::vector<Touch*> _touches 来记录该事件相关的touch,值得注意的是。本版本号默认含有的触摸点最大是5个。


2.1.3 EventCustom


     EventCustom的出现代替了统治2.x版本号多年的NotificationCenter,来看下EventCustom的两个重要成员变量。

    void* _userData;       ///< User data
std::string _eventName;

有没有似曾相识的感觉,还是一样的key。还是一样的userData(有点不一样。原来是CCObject*)。



       其它的Event由于重要性以及使用度的原因,这里不再赘述,假设以后笔者对他们有新的认识。将会在这里进行加入。

2.2 EventListener相关

2.2.1 EventListener


     
    std::function<void(Event*)> _onEvent;   /// Event callback function
Type _type; /// Event listener type
ListenerID _listenerID; /// Event listener ID
bool _isRegistered; /// Whether the listener has been added to dispatcher. int _fixedPriority; // The higher the number, the higher the priority, 0 is for scene graph base priority.
Node* _node; // scene graph based priority
bool _paused; // Whether the listener is paused
bool _isEnabled; // Whether the listener is enabled

       重要的成员变量:
      1.onEvent,是绑定于该Listener的callback function,该func的声明使用了c++11的新特性。

      2.type与Event类似。添加一个Unknown的属性。
      3.isRegistered变量很重要,假设他没有被注冊。则他的事件不会触发。
      4.优先级代表了响应一个事件时的顺序。该值越低。越先响应。
      5.node 代表了与该listener相关的node,用于 scene graph类的事件响应,详细的在Dispatcher里面有进行介绍。
      6.最后说下ListenerID,这是该类型事件的标识符。除了EventCustomListener的ListerID是与name相关的。其余的ListenerID都是固定的。用于标识该类EventListener。


     
 /** Enables or disables the listener
* @note Only listeners with `enabled` state will be able to receive events.
* When an listener was initialized, it's enabled by default.
* An event listener can receive events when it is enabled and is not paused.
* paused state is always false when it is a fixed priority listener.
*/
inline void setEnabled(bool enabled) { _isEnabled = enabled; };
/** Sets paused state for the listener
* The paused state is only used for scene graph priority listeners.
* `EventDispatcher::resumeAllEventListenersForTarget(node)` will set the paused state to `true`,
* while `EventDispatcher::pauseAllEventListenersForTarget(node)` will set it to `false`.
* @note 1) Fixed priority listeners will never get paused. If a fixed priority doesn't want to receive events,
* call `setEnabled(false)` instead.
* 2) In `Node`'s onEnter and onExit, the `paused state` of the listeners which associated with that node will be automatically updated.
*/
inline void setPaused(bool paused) { _paused = paused; };

上面两段话。解释了什么时候一个Listener是能够接收事件,什么时候是不能够的。

       1.一个Listener想接收事件必须是enabled true 而且 paused false。
      2.值得注意的是,pause的变量专门是为了scenGraph类的事件存在的(兴许有说明),并且一个Node的onEnter和onExit 事件会影响到与Node相关的该类事件的pause状态。

2.2.2 EventListenerOneByOne


     
    /// Overrides
virtual EventListenerTouchOneByOne* clone() override;
virtual bool checkAvailable() override;
// public:
std::function<bool(Touch*, Event*)> onTouchBegan;
std::function<void(Touch*, Event*)> onTouchMoved;
std::function<void(Touch*, Event*)> onTouchEnded;
std::function<void(Touch*, Event*)> onTouchCancelled;

        上面的是OneByOne重载父类的方法。以及自己本身须要被绑定4个callBack 函数。

        
        
EventListenerTouchOneByOne* EventListenerTouchOneByOne::clone()
{
//深拷贝
auto ret = new EventListenerTouchOneByOne();
if (ret && ret->init())
{
ret->autorelease(); ret->onTouchBegan = onTouchBegan;
ret->onTouchMoved = onTouchMoved;
ret->onTouchEnded = onTouchEnded;
ret->onTouchCancelled = onTouchCancelled; ret->_claimedTouches = _claimedTouches;
ret->_needSwallow = _needSwallow;
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}


bool EventListenerTouchOneByOne::checkAvailable()
{
// EventDispatcher will use the return value of 'onTouchBegan' to determine whether to pass following 'move', 'end'
// message to 'EventListenerTouchOneByOne' or not. So 'onTouchBegan' needs to be set.
//OneByOne仅仅须要onTouchBegan不为空,则能够觉得其是可用的。 if (onTouchBegan == nullptr)
{
CCASSERT(false, "Invalid EventListenerTouchOneByOne!");
return false;
} return true;
}

什么是可用性,当在dispatcher进行事件分发时,假设一个Listener是不可用的。则不会将该事件分发给他。


    std::vector<Touch*> _claimedTouches;
bool _needSwallow;

OneByOne的touch是能够设置吞噬属性的。

2.2.3 EventListenerAllAtOnce

        
    std::function<void(const std::vector<Touch*>&, Event*)> onTouchesBegan;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesMoved;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesEnded;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesCancelled;

        AllAtOnce就是所谓的standard touch处理机制。一次性处理全部的touch。

       值得注意的是AllAtOnce的checkAvailable要求,上述四个函数指针都不能为空。


       
bool EventListenerTouchAllAtOnce::checkAvailable()
{
if (onTouchesBegan == nullptr && onTouchesMoved == nullptr
&& onTouchesEnded == nullptr && onTouchesCancelled == nullptr)
{
CCASSERT(false, "Invalid EventListenerTouchAllAtOnce!");
return false;
} return true;
}

2.3 EventListenerCustom


       相同的。EventListenerID是依据独特的Name进行命名的,值得注意的是请确保你的name是具有唯一性的,否在在DispatchCustomEvent时会有问题。


3. EventDispatcher

       从头到尾写了这么多,才開始进入主题。上面的东西都是为了看EventDispatcher源代码的开胃菜!!!在介绍这个之前,我们必需要看一个内部类

3.1 EventListenerVector


      
class EventListenerVector
{
public:
EventListenerVector();
~EventListenerVector();
size_t size() const;
bool empty() const; void push_back(EventListener* item);
void clearSceneGraphListeners();
void clearFixedListeners();
void clear(); inline std::vector<EventListener*>* getFixedPriorityListeners() const { return _fixedListeners; };
inline std::vector<EventListener*>* getSceneGraphPriorityListeners() const { return _sceneGraphListeners; };
inline ssize_t getGt0Index() const { return _gt0Index; };
inline void setGt0Index(ssize_t index) { _gt0Index = index; };
private:
std::vector<EventListener*>* _fixedListeners;
std::vector<EventListener*>* _sceneGraphListeners;
ssize_t _gt0Index;
};

        首先我要说明的是两个很很重要的变量。fixedListeners和sceneGraphListeners。这是两个截然不同的Listener列表。
        1.sceneGraph类型的事件,是与当前正在执行的scene下node相关的事件,也就是说一个事件(比方说触摸事件),须要依照一定的响应序列。依次对这些Node进行事件响应,所以该类型的事件都会绑定一个与此相关联的node,而且响应顺序是与node在scene下的zorder相关的。该类型下的事件优先级统一为0.
        2.fixed类型的事件相对就比較简单了,可是有一个限制就是其优先级不能为0.

在EventDispatcher的成员变量中有一个map :std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap;  一种ListenerID相应了一个Vector。

       
size_t EventDispatcher::EventListenerVector::size() const
{
//vector内部的size大小是两个list的和
size_t ret = 0;
if (_sceneGraphListeners)
ret += _sceneGraphListeners->size();
if (_fixedListeners)
ret += _fixedListeners->size(); return ret;
}


void EventDispatcher::EventListenerVector::push_back(EventListener* listener)
{
//查看listener的priority。假设为0,增加sceneGraphList,否则增加fixedList
if (listener->getFixedPriority() == 0)
{
if (_sceneGraphListeners == nullptr)
{
_sceneGraphListeners = new std::vector<EventListener*>();
_sceneGraphListeners->reserve(100);
} _sceneGraphListeners->push_back(listener);
}
else
{
if (_fixedListeners == nullptr)
{
_fixedListeners = new std::vector<EventListener*>();
_fixedListeners->reserve(100);
} _fixedListeners->push_back(listener);
}
}

上面两个函数是与一般Vector不一样的地方。须要注意的地方我已经标注了凝视。



3.2 Add操作

       既然是一个类似于Manager的类,那就先从Add操作開始吧。


       三种事件的加入方式:

3.2.1 sceneGraph类

  
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
{
CCASSERT(listener && node, "Invalid parameters.");
CCASSERT(!listener->isRegistered(), "The listener has been registered."); //检查Listener可用性
if (!listener->checkAvailable())
return;
//设置listener相关属性
listener->setAssociatedNode(node);
listener->setFixedPriority(0);
listener->setRegistered(true); addEventListener(listener);
}

3.2.2 fixed类

     
void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
{
CCASSERT(listener, "Invalid parameters.");
//一个事件仅仅能被注冊一次
CCASSERT(!listener->isRegistered(), "The listener has been registered.");
//Fixed类型的事件优先级不能是0
CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority."); //检查可用性
if (!listener->checkAvailable())
return; //设置关联属性
listener->setAssociatedNode(nullptr);
listener->setFixedPriority(fixedPriority);
listener->setRegistered(true);
listener->setPaused(false); addEventListener(listener);
}

3.2.3 custom类

EventListenerCustom* EventDispatcher::addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback)
{
//custom类的事件加入是通过eventName 和 eventcallBack来进行加入的
EventListenerCustom *listener = EventListenerCustom::create(eventName, callback); //custom的事件优先级被默觉得1
addEventListenerWithFixedPriority(listener, 1); return listener;
}

能够看出,加入函数最后都用到了一个函数addEventListener,以下对其进行剖析(这个函数又用到了其它函数。又。又,又。。

。。

。)


3.2.4 addEventListener

void EventDispatcher::addEventListener(EventListener* listener)
{
//假设当前Dispatcher正在进行事件Dispatch,则放到toAddList中。
if (_inDispatch == 0)
{
forceAddEventListener(listener);
}
else
{
// std::vector
_toAddedListeners.push_back(listener);
} listener->retain();
}

3.2.5 forceAddEventListener


   
void EventDispatcher::forceAddEventListener(EventListener* listener)
{
EventListenerVector* listeners = nullptr;
EventListener::ListenerID listenerID = listener->getListenerID(); //找到该类eventlistener的vector。此处的vector是EventVector
auto itr = _listenerMap.find(listenerID);
//假设没有找到,则须要向map中加入一个pair
if (itr == _listenerMap.end())
{ listeners = new EventListenerVector();
_listenerMap.insert(std::make_pair(listenerID, listeners));
}
else
{
listeners = itr->second;
}
//将该类别listenerpush_back进去(这个函数调用的是EventVector的pushback哦)
listeners->push_back(listener); //假设优先级是0。则设置为graph。
if (listener->getFixedPriority() == 0)
{
//设置该listenerID的DirtyFlag
//(setDirty函数能够这样理解,每一个ListenerID都有特定的dirtyFlag。每次进行add操作后,都要更新该ID的flag)
setDirty(listenerID, DirtyFlag::SCENE_GRAPH_PRIORITY); //假设是sceneGraph类的事件。则须要处理两个方面:
//1.将node 与event 关联
//2.假设该node是执行中的。则须要恢复其事件(由于默认的sceneGraph listener的状态时pause)
//添加该listener与node的关联
auto node = listener->getAssociatedNode();
CCASSERT(node != nullptr, "Invalid scene graph priority!"); associateNodeAndEventListener(node, listener); //恢复node的执行状态
if (node->isRunning())
{
resumeEventListenersForTarget(node);
}
}
else
{
setDirty(listenerID, DirtyFlag::FIXED_PRIORITY);
}
}

3.2.6associateNodeAndEventListener

   
void EventDispatcher::associateNodeAndEventListener(Node* node, EventListener* listener)
{
//将listener与node关联,先从map中找到与该node相关的listener vector
std::vector<EventListener*>* listeners = nullptr;
auto found = _nodeListenersMap.find(node);
if (found != _nodeListenersMap.end())
{
listeners = found->second;
}
else
{
listeners = new std::vector<EventListener*>();
_nodeListenersMap.insert(std::make_pair(node, listeners));
}
//vector内加入该listener,这里的vector 是std::vector
listeners->push_back(listener);
}

3.2.7  removeEventListenersForTarget


     
void EventDispatcher::resumeEventListenersForTarget(Node* target, bool recursive/* = false */)
{
//恢复Node的执行状态
auto listenerIter = _nodeListenersMap.find(target);
if (listenerIter != _nodeListenersMap.end())
{
auto listeners = listenerIter->second;
for (auto& l : *listeners)
{
l->setPaused(false);
}
}
// toAdd List中也要进行恢复
for (auto& listener : _toAddedListeners)
{
if (listener->getAssociatedNode() == target)
{
listener->setPaused(false);
}
}
//将该Node 与 node的child 都放到dirtyNode中,来记录与event相关的node
setDirtyForNode(target); if (recursive)
{
const auto& children = target->getChildren();
for (const auto& child : children)
{
resumeEventListenersForTarget(child, true);
}
}
}

3.3 Remove

        看完了Add。当然要讲remove

3.3.1 removeEventListener

     
void EventDispatcher::removeEventListener(EventListener* listener)
{
//说在前面,移除一个事件的代价比較大,假设没有必要,请不要无故移除事件。
//删除一个listener的步骤:
if (listener == nullptr)
return; bool isFound = false; //lambda函数。函数从std::vector<EventListener*>* listeners 中移除该listener
auto removeListenerInVector = [&](std::vector<EventListener*>* listeners){
if (listeners == nullptr)
return;
//遍历
for (auto iter = listeners->begin(); iter != listeners->end(); ++iter)
{
auto l = *iter;
if (l == listener)
{
//找到后的处理方法,标记状态位,并处理关联Node
CC_SAFE_RETAIN(l);
l->setRegistered(false);
if (l->getAssociatedNode() != nullptr)
{
dissociateNodeAndEventListener(l->getAssociatedNode(), l);
l->setAssociatedNode(nullptr); // NULL out the node pointer so we don't have any dangling pointers to destroyed nodes.
}
//当前没有在分发事件 则直接从listeners中移除该listener(由于标记了状态未。假设此时在分发事件。则会等结束后再移除)
if (_inDispatch == 0)
{
listeners->erase(iter);
CC_SAFE_RELEASE(l);
} isFound = true;
break;
}
}
}; for (auto iter = _listenerMap.begin(); iter != _listenerMap.end();)
{
//从listenersmap 中遍历全部。拿出全部的vector
auto listeners = iter->second;
auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); //从graphList中寻找。 找到后须要更新该listenerID的dirty flag。
removeListenerInVector(sceneGraphPriorityListeners);
if (isFound)
{
// fixed #4160: Dirty flag need to be updated after listeners were removed.
setDirty(listener->getListenerID(), DirtyFlag::SCENE_GRAPH_PRIORITY);
}
//从fixedList中寻找
else
{
removeListenerInVector(fixedPriorityListeners);
if (isFound)
{
setDirty(listener->getListenerID(), DirtyFlag::FIXED_PRIORITY);
}
} //假设vector在删除后是空的,则须要移除该vector。而且将对应的listenerID从_priorityDirtyFlagMap中移除。
if (iter->second->empty())
{
_priorityDirtyFlagMap.erase(listener->getListenerID());
auto list = iter->second;
iter = _listenerMap.erase(iter);
CC_SAFE_DELETE(list);
}
else
{
++iter;
} if (isFound)
break;
} if (isFound)
{
CC_SAFE_RELEASE(listener);
}
//假设在上述过程中未找到。则从toAddList中寻找
else
{
for(auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end(); ++iter)
{
if (*iter == listener)
{
listener->setRegistered(false);
listener->release();
_toAddedListeners.erase(iter);
break;
}
}
}
}

3.3.2  removeEventListenersForListenerID


 
void EventDispatcher::removeEventListenersForListenerID(const EventListener::ListenerID& listenerID)
{
auto listenerItemIter = _listenerMap.find(listenerID);
if (listenerItemIter != _listenerMap.end())
{
auto listeners = listenerItemIter->second;
auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); //啊哦 又是一个lambda函数。将std::vector<EventListener*>* listenerVector中的Listener所有移除
auto removeAllListenersInVector = [&](std::vector<EventListener*>* listenerVector){
if (listenerVector == nullptr)
return; for (auto iter = listenerVector->begin(); iter != listenerVector->end();)
{
//设置要删除的listener状态,清空与其相关的node信息
auto l = *iter;
l->setRegistered(false);
if (l->getAssociatedNode() != nullptr)
{
dissociateNodeAndEventListener(l->getAssociatedNode(), l);
l->setAssociatedNode(nullptr); // NULL out the node pointer so we don't have any dangling pointers to destroyed nodes.
} if (_inDispatch == 0)
{
iter = listenerVector->erase(iter);
CC_SAFE_RELEASE(l);
}
else
{
++iter;
}
}
}; //两种类型的事件哦
removeAllListenersInVector(sceneGraphPriorityListeners);
removeAllListenersInVector(fixedPriorityListeners); // Remove the dirty flag according the 'listenerID'.
// No need to check whether the dispatcher is dispatching event.
_priorityDirtyFlagMap.erase(listenerID); if (!_inDispatch)
{
listeners->clear();
delete listeners;
_listenerMap.erase(listenerItemIter);
}
} //toAddList 的清理,真可怜,还没来得及进入家门就要被扫地出门了么。。。。
for (auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end();)
{
if ((*iter)->getListenerID() == listenerID)
{
(*iter)->setRegistered(false);
(*iter)->release();
iter = _toAddedListeners.erase(iter);
}
else
{
++iter;
}
}
}

     与其相关的两个remove函数

    
void EventDispatcher::removeEventListenersForType(EventListener::Type listenerType)
{
if (listenerType == EventListener::Type::TOUCH_ONE_BY_ONE)
{
removeEventListenersForListenerID(EventListenerTouchOneByOne::LISTENER_ID);
}
else if (listenerType == EventListener::Type::TOUCH_ALL_AT_ONCE)
{
removeEventListenersForListenerID(EventListenerTouchAllAtOnce::LISTENER_ID);
}
else if (listenerType == EventListener::Type::MOUSE)
{
removeEventListenersForListenerID(EventListenerMouse::LISTENER_ID);
}
else if (listenerType == EventListener::Type::ACCELERATION)
{
removeEventListenersForListenerID(EventListenerAcceleration::LISTENER_ID);
}
else if (listenerType == EventListener::Type::KEYBOARD)
{
removeEventListenersForListenerID(EventListenerKeyboard::LISTENER_ID);
}
else
{
CCASSERT(false, "Invalid listener type!");
}
}

   
void EventDispatcher::removeCustomEventListeners(const std::string& customEventName)
{
removeEventListenersForListenerID(customEventName);
}

3.3.3 removeAllEventListeners

  
void EventDispatcher::removeAllEventListeners()
{
bool cleanMap = true;
std::vector<EventListener::ListenerID> types(_listenerMap.size()); for (const auto& e : _listenerMap)
{
if (_internalCustomListenerIDs.find(e.first) != _internalCustomListenerIDs.end())
{
cleanMap = false;
}
else
{
types.push_back(e.first);
}
} for (const auto& type : types)
{
removeEventListenersForListenerID(type);
} if (!_inDispatch && cleanMap)
{
_listenerMap.clear();
}
}


3.4 DispatchEvent(核心内容)

     最终到了核心内容了。为啥我要把核心内容放到后面。假设不看上面,不了解Event。EventListener,EventVector以及Dispatcher是怎样管理EventListener的。看以下的代码就会有非常多的疑惑。

ok,让我们静静赞赏源代码吧。


3.4.1 dispatchEvent

    
void EventDispatcher::dispatchEvent(Event* event)
{
if (!_isEnabled)
return; //为dirtyNodesVector中的dirtyNode更新Scene Flag。 updateDirtyFlagForSceneGraph(); DispatchGuard guard(_inDispatch); //特殊touch事件,转到特殊的touch事件处理
if (event->getType() == Event::Type::TOUCH)
{
dispatchTouchEvent(static_cast<EventTouch*>(event));
return;
} //依据事件的类型。获取事件的ID
auto listenerID = __getListenerID(event); //依据事件ID,将该类事件进行排序(先响应谁)
sortEventListeners(listenerID); auto iter = _listenerMap.find(listenerID);
if (iter != _listenerMap.end())
{
auto listeners = iter->second;
//该类事件的lambda函数
auto onEvent = [&event](EventListener* listener) -> bool{
//设置event的target
event->setCurrentTarget(listener->getAssociatedNode());
//调用响应函数
listener->_onEvent(event);
//返回是否已经停止
return event->isStopped();
}; //将该类事件的listeners 和 该类事件的 lambda函数传给该函数
dispatchEventToListeners(listeners, onEvent);
} //更新该事件相关的listener
updateListeners(event);
}

    我们能够看出,特殊的touchEvent和普通的event走的不是同一条控制流程,既然如此,我们就先一般后特殊吧。先来看看一般流程下的DispatchEventToListeners吧

3.4.2 dispatchEventToListeners


  
void EventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent)
{
bool shouldStopPropagation = false;
auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); //总体操作流程分为三个部分,处理优先级<0,=0,>0三个部分
ssize_t i = 0;
// priority < 0
if (fixedPriorityListeners)
{
CCASSERT(listeners->getGt0Index() <= static_cast<ssize_t>(fixedPriorityListeners->size()), "Out of range exception!"); if (!fixedPriorityListeners->empty())
{
for (; i < listeners->getGt0Index(); ++i)
{
auto l = fixedPriorityListeners->at(i);
// onEvent(l)的操作调用了event的callBack,而且会返回是否停止,假设停止后,则将shouldStopPropagation标记为true
//在其后面的listeners则不会响应到该事件(这里能够看出触摸事件是怎样被吞噬的)
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
}
} if (sceneGraphPriorityListeners)
{
if (!shouldStopPropagation)
{
// priority == 0, scene graph priority
for (auto& l : *sceneGraphPriorityListeners)
{
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
}
} if (fixedPriorityListeners)
{
if (!shouldStopPropagation)
{
// priority > 0
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;
}
}
}
}
}

3.4.3 dispatchTouchEvent(3.x版本号的触摸机制)

       
void EventDispatcher::dispatchTouchEvent(EventTouch* event)
{
//先将EventListeners排序
sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);
sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID); auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID);
auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID); // If there aren't any touch listeners, return directly.
if (nullptr == oneByOneListeners && nullptr == allAtOnceListeners)
return; //mutableTouches是用来处理allAtOnce的
bool isNeedsMutableSet = (oneByOneListeners && allAtOnceListeners); //这些touch都来自该事件
const std::vector<Touch*>& originalTouches = event->getTouches();
std::vector<Touch*> mutableTouches(originalTouches.size());
std::copy(originalTouches.begin(), originalTouches.end(), mutableTouches.begin()); //
// process the target handlers 1st
//
if (oneByOneListeners)
{
auto mutableTouchesIter = mutableTouches.begin();
auto touchesIter = originalTouches.begin();
//遍历touches,每个touch都来自于同一个事件
for (; touchesIter != originalTouches.end(); ++touchesIter)
{
bool isSwallowed = false; //事件处理的lambda函数
auto onTouchEvent = [&](EventListener* l) -> bool { // Return true to break
EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l); // Skip if the listener was removed.
if (!listener->_isRegistered)
return false; event->setCurrentTarget(listener->_node);
//claimed代表该listener是否接收了该touch(Began返回true or false)
bool isClaimed = false;
std::vector<Touch*>::iterator removedIter; //依据eventNode的不同,会调用不同的callBack函数
EventTouch::EventCode eventCode = event->getEventCode(); if (eventCode == EventTouch::EventCode::BEGAN)
{
//调用began
if (listener->onTouchBegan)
{
isClaimed = listener->onTouchBegan(*touchesIter, event);
if (isClaimed && listener->_isRegistered)
{
//返回true后 将该touch放入该listener的claimedTouches
listener->_claimedTouches.push_back(*touchesIter);
}
}
}
//假设是后三个move end cancel
else if (listener->_claimedTouches.size() > 0
&& ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end()))
{
isClaimed = true;
//调用对应的callBack
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;
case EventTouch::EventCode::CANCELLED:
if (listener->onTouchCancelled)
{
listener->onTouchCancelled(*touchesIter, event);
}
if (listener->_isRegistered)
{
listener->_claimedTouches.erase(removedIter);
}
break;
default:
CCASSERT(false, "The eventcode is invalid.");
break;
}
} // If the event was stopped, return directly.
if (event->isStopped())
{
updateListeners(event);
return true;
} CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), ""); //假设接收该touch而且须要吞噬该touch。会有两个影响
//1.Touches(standard 触摸机制)的触摸操作都接收不到该touch了
//2.由于返回值是true,在调用dispatchEventToListeners时。在该node之后的node将会不再接收该touch
if (isClaimed && listener->_isRegistered && listener->_needSwallow)
{
if (isNeedsMutableSet)
{
mutableTouchesIter = mutableTouches.erase(mutableTouchesIter);
isSwallowed = true;
}
return true;
} return false;
}; //结合上面的dispatchEventToListeners的源代码分析。能够看出新版本号的OneByOne touch机制是这种:
//1.listener依据Node的优先级排序后。依次响应。 值得注意的是,新版本号的优先级是依据Node的global Zorder来的。而不是2.x的触摸优先级。 //2.当TouchEvent Began来了之后,全部的listener会依次影响Touch Began。 然后再依次响应Touch Move...而不是一个listener响应完
//began move end之后 轮到下一个listener响应的顺序。
//3.吞噬操作仅仅有发生在began return true后才干够发生
dispatchEventToListeners(oneByOneListeners, onTouchEvent);
if (event->isStopped())
{
return;
} if (!isSwallowed)
++mutableTouchesIter;
}
} //
// process standard handlers 2nd
//
//相比于OneByOne。AllAtOnce要简单很多。值得注意的是被吞噬的touch也不会被AllAtOnce响应到
if (allAtOnceListeners && mutableTouches.size() > 0)
{ auto onTouchesEvent = [&](EventListener* l) -> bool{
EventListenerTouchAllAtOnce* listener = static_cast<EventListenerTouchAllAtOnce*>(l);
// Skip if the listener was removed.
if (!listener->_isRegistered)
return false; 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 eventcode is invalid.");
break;
} // If the event was stopped, return directly.
if (event->isStopped())
{
updateListeners(event);
return true;
} return false;
}; dispatchEventToListeners(allAtOnceListeners, onTouchesEvent);
if (event->isStopped())
{
return;
}
} updateListeners(event);
}

      非常多须要注意的地方我全给了中文标识。可是这里我还要再次说明下新版本号的touch OneByOne机制:
      1.listener依据Node的优先级排序后。依次响应。值得注意的是,新版本号的优先级是依据Node的global Zorder来的,而不是2.x的触摸优先级。

       2.当TouchEvent Began来了之后,全部的listener会依次影响Touch Began。然后再依次响应Touch Move...而不是一个listener响应完  began move end之后 轮到下一个listener响应的顺序。

        3.吞噬操作仅仅有发生在began return true后才干够发生

3.4.4 DispatchCustomEvent (新版本号的NotificationCenter机制)

    
void EventDispatcher::dispatchCustomEvent(const std::string &eventName, void *optionalUserData)
{
EventCustom ev(eventName);
ev.setUserData(optionalUserData);
dispatchEvent(&ev);
}

好简单,这个函数像不像 postNotification(......)?,在3.x的事件中。再也不要使用NotificationCenter了哦~

4.小结

      Event,EventListener,EventDispatcher的关系
      新的触摸机制
      新的NotificationCenter方法

cocos2d-x 源代码分析 : EventDispatcher、EventListener、Event 源代码分析 (新触摸机制,新的NotificationCenter机制)的更多相关文章

  1. qemu-kvm-1.1.0源代码中关于迁移的代码分析

    这篇文档基于qemu-kvm-1.1.0源代码进行分析. 首先,源代码中的hmp-commands.hx文件里有下面内容: { .name = "migrate",/* 在moni ...

  2. cocos2d游戏界面卡住声音正常播放的问题分析

    cocos2d游戏界面卡住声音正常播放的问题分析 从目前已知的情况看,出现这种情况只可能是设备的内存不够导致的. 从代码上来说内存不够时会调用AppController的“- (void)applic ...

  3. Envoy 源码分析--event

    目录 Envoy 源码分析--event libevent Timer SignalEvent FileEvent RealTimeSystem 任务队列 延迟析构 dispacth_thread E ...

  4. 3. 上网调查一下目前流行的源程序版本管理软件和项目管理软件都有哪些, 各有什么优缺点? (提示:搜索一下Microsoft TFS、GitHub、Trac、Bugzilla、Rationale,Apple XCode),请用一个实际的源代码管理工具来建立源代码仓库,并签入/签出代码。

    上网调查一下目前流行的源程序版本管理软件和项目管理软件都有哪些, 各有什么优缺点? ---------------答题者:徐潇瑞 (1)Microsoft TFS的优缺点: 优点:是对敏捷,msf,c ...

  5. Laravel Event的分析和使用

    Laravel Event的分析和使用 第一部分 概念解释 请自行查看观察者模式 第二部分 源码分析 (逻辑较长,不喜欢追代码可以直接看使用部分) 第三部分 使用 第一部分 解释 当一个用户阅读了一篇 ...

  6. 性能分析之-- JAVA Thread Dump 分析综述

    性能分析之-- JAVA Thread Dump 分析综述       一.Thread Dump介绍 1.1什么是Thread Dump? Thread Dump是非常有用的诊断Java应用问题的工 ...

  7. 8、SpringMVC源码分析(3):分析ModelAndView的形成过程

    首先,我们还是从DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) throw ...

  8. 【linux驱动分析】之dm9000驱动分析(三):sk_buff结构分析

    [linux驱动分析]之dm9000驱动分析(一):dm9000原理及硬件分析 [linux驱动分析]之dm9000驱动分析(二):定义在板文件里的资源和设备以及几个宏 [linux驱动分析]之dm9 ...

  9. k8s garbage collector分析(1)-启动分析

    k8s garbage collector分析(1)-启动分析 garbage collector介绍 Kubernetes garbage collector即垃圾收集器,存在于kube-contr ...

随机推荐

  1. nginx+php-fpm 配置和错误总结

    <strong>空白页面:</strong>需要这个参数: fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_scrip ...

  2. TCP长连接与短链接

    1. TCP连接 当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次 ...

  3. CentOS 6.9/7通过yum安装指定版本的Tomcat

    说明:通过yum好处其实很多,环境变量不用配置,配置文件放在大家都熟悉的地方,通过rpm -ql xxx可以知道全部文件的地方等等. 一.安装Tomcat(8+) // 下载脚本 # git clon ...

  4. keystone 命令简要说明

    catalog: keystone catalog 可以显示所有已有的service keystone catalog --service service-type 显示某个service信息 end ...

  5. [转]C#中图片.BYTE[]和base64string的转换

    本文转自:http://blog.csdn.net/thebesttome/article/details/6870155 在C#中 图片到byte[]再到base64string的转换: Bitma ...

  6. 编写第一个Shell脚本

    Linux中有好多中不同的shell,bash是linux默认的shell,免费且容易使用. su切换为root权限 1.创建shell脚本 touch hello.sh 2.编辑: vi hello ...

  7. .NET:为什么不能在子类或外部发布C#事件

    背景 一个朋友问了一个问题:“为什么不能在子类或外部发布C#事件?”,我说我不知道,要看看生产的IL代码,下面我们看看. 测试 代码 using System; using System.Collec ...

  8. 3DPrint ABS和PLA代码比较

    PLA ABS

  9. 分享一个 markdown 编辑器 - Mditor

    只求极致 [ M ] arkdown + E [ ditor ] = Mditor Mditor 是一个简洁.易于集成.方便扩展.期望舒服的编写 markdown 的编辑器,仅此而已... 主页: h ...

  10. gpu和cpu区别

    GPU的功耗远远超过CPUCache, local memory: CPU > GPU Threads(线程数): GPU > CPURegisters: GPU > CPU 多寄存 ...