cocos2d-x 源码分析 : EventDispatcher、EventListener、Event 源码分析 (新触摸机制,新的NotificationCenter机制)

源码版本来自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机制)

时间: 2024-10-15 21:35:01

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

cocos2d-x 源代码分析 : EventDispatcher、EventListener、Event 源代码分析 (新触摸机制,新的NotificationCenter机制)

源代码版本号来自3.x,转载请注明 cocos2d-x 源代码分析总文件夹 http://blog.csdn.net/u011225840/article/details/31743129 1.继承结构 1.1 结构 不详吐槽太多,也不贴图了.贴图要审核好久好久好久好久. 从小到大,先来看下Event的结构. 1.Event--------EventTouch,EventCustom,EventMouse,EventKeyboard,EventFocus,EventAcceleration 当中

Cocos2d-X3.0 刨根问底(七)----- 事件机制Event源码分析

这一章,我们来分析Cocos2d-x 事件机制相关的源码, 根据Cocos2d-x的工程目录,我们可以找到所有关于事件的源码都存在放在下图所示的目录中. 从这个event_dispatcher目录中的文件命名上分析 cocos2d-x与事件相关的类一共有四种, Event, EventListener,EventDispatcher, Touch分别为 事件,事件侦听器,事件分发器,触摸 我们先从Event类开始. 打开CCEvent.h文件 /** * Base class of all ki

[转] jQuery源码分析-如何做jQuery源码分析

jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书>结合起来进行学习.推荐读读这本书,你可以从这里和这里下载. 第一部分:检视阅读 1. 收集参考资料:官方文档.书籍.百度/谷歌,专题/博客等,快速的浏览,对涉及的知识点.范围.深度.是否有参考意义等有大致的了解和判断,知道这些文章的作者想要解释或解决什么问题. 第二部分:分析阅读 2. 细读官方文档,官方有非

传奇源码分析-客户端(游戏逻辑处理源分析四)

现在假设玩家开始操作游戏:传奇的客户端源代码工程WindHorn一.CWHApp派生CWHWindow和CWHDXGraphicWindow.二.CWHDefProcess派生出CloginProcess.CcharacterProcess.CgameProcess客户端WinMain调用CWHDXGraphicWindow g_xMainWnd;创建一个窗口.客户端CWHDXGraphicWindow在自己的Create函数中调用了CWHWindow的Create来创建窗口,然后再调用自己的C

传奇源码分析-客户端(游戏逻辑处理源分析五 服务器端响应)

器执行流程:(玩家走动) GameSrv服务器ProcessUserHuman线程处理玩家消息:遍历UserInfoList列表,依次调用每个UserInfo的Operate来处理命令队列中的所有操作; pUserInfo->Operate()调用m_pxPlayerObject->Operate()调用.判断玩家if (!m_fIsDead),如果已死,则发送_MSG_FAIL消息.我们在前面看到过,该消息是被优先处理的.否则则调用WalkTo,并发送_MSG_GOOD消息给客户端.Walk

传奇源码分析-客户端(游戏逻辑处理源分析三)

6. 接收怪物,商人,其它玩家的消息:ProcessUserHuman:(其它玩家-服务器处理)CPlayerObject->SearchViewRange();CPlayerObject->Operate();遍历UserInfoList列表,依次调用每个UserInfo的Operate来处理命令队列中的所有操作; pUserInfo->Operate()调用m_pxPlayerObject->Operate()调用.根据分发消息(RM_TURN)向客户端发送SM_TURN消息.

传奇源码分析-客户端(游戏逻辑处理源分析二)

5.接受登录成功后,接收GameSrv服务器发送的消息:接收GameGate发送的消息:CClientSocket::OnSocketMessage的FD_READ事件中,PacketQ.PushQ((BYTE*)pszPacket);把接收到的消息,压入PacketQ队列中.处理PacketQ队列数据是由CGameProcess::Load()时调用OnTimer在CGameProcess::OnTimer中处理的, 处理过程为:OnMessageReceive; ProcessPacket(

Java集合源码学习笔记(二)ArrayList分析

Java集合源码学习笔记(二)ArrayList分析 >>关于ArrayList ArrayList直接继承AbstractList,实现了List. RandomAccess.Cloneable.Serializable接口,为什么叫"ArrayList",因为ArrayList内部是用一个数组存储元素值,相当于一个可变大小的数组,也就是动态数组. (1)继承和实现继承了AbstractList,实现了List:ArrayList是一个数组队列,提供了相关的添加.删除.修

ConcurrentHashMap源码阅读以及底层实现的简单分析

ConcurrentHashMap 是可以实现多线程并发的HashMap,它是线程安全的. 前面分析过 HashMap的源码,它和HashMap有很多的相同点一样,比如它也有 initialCapacity 以及负载因子 loadFactor 属性.而且他们的默认值也是16和0.75. static final int DEFAULT_INITIAL_CAPACITY =16; static final float DEFAULT_LOAD_FACTOR =0.75f; 和HashMap不同的是