Cocos2dx Engine 10-event dispatch

Source: Internet
Author: User

Cocos2dx Engine 10-event dispatch

This article describes the Event distribution module in the Cocos2dx Event processing mechanism. After an Event occurs, it processes a series of events and distributes the events;

1. dispatchEvent & dispatchTouchEvent Method

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);}
 

In the dispatchEvent method:

(1) Determine whether the Event distribution mechanism is enabled

(2) Update dirty data flag

(3) Distribution of touch events

(4) distribute other types of events

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);}
  
 

In the dispatchTouchEvent method:

(1) sort the list of single-click and multi-click EventListener; of course, in the sorting algorithm, first determine whether the current EventListener list is dirty data. If it is dirty data, sort it; details of sorting are described below

(2) retrieve the list of single-click and multi-click EventListener and determine whether EventListener is empty

(3) Obtain Event information

(4) If the single-click EventListener list is not empty

(5) If the EventListener list is not empty

(6) Update the EventListener list status

2. EvnetListener sorting in the dispatchTouchEvent method sortEventListeners

The sortEventListeners method is used in the dispatchTouchEvent method to sort the EventListener list. The method is described in detail below;

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;            }        }    }}

In the sortEventListeners method:

(1) check whether the EventListener of the listenerID has dirty data in the dirty data list. If there is no dirty data, do not sort it. Exit this method. If there is dirty data, sort it.

(2) Sort EventListener lists with priority not equal to 0.

(3) sort the EventListener list with a priority of 0.

The following shows how to sort the EventListener list with a priority not equal to 0:

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);}
 

In the sortEventListenersOfFixedPriority method:

(1) obtain the EventListener list based on the ID and determine whether the list is empty.

(2) obtain the EventListener LIST _ fixedListeners whose priority is not 0 in the EventListener list

(3) Use the sort method in STL to sort the _ fixedListeners method from small to large

(4) count the number of EventListener whose priority value is less than 0 in the fixedListeners table

It can be learned from the sorting method that the EventListener with a higher priority (smaller value) is executed first. If the priority is the same, the registered EventListener is executed first.

The following shows how to sort the EventListener list with a priority of 0:

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()];    });}

In the sortEventListenersOfSceneGraphPriority method:

(1) obtain the EventListener list based on the ID and determine whether the list is empty.

(2) obtain the EventListener list with a priority of 0 in the EventListener LIST _ sceneGraphListeners

(3) Use the _ globalZOrder value to sort nodes in the Scene.

(4) sort the _ sceneGraphListeners list from large to small Based on the _ globalZOrder value of the Node corresponding to EventListener.

3,The dispatchEventToListeners method in the dispatchTouchEvent Method

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;                }            }        }    }}
  
 

In the dispatchEventToListeners function:

(1) Get the _ fixedListeners & _ sceneGraphListeners list

(2) When _ fixedListeners is not empty, perform EventToListener processing in the _ fixedListeners class table.

(3) When _ sceneGraphListeners is not empty, execute EventToListener processing in the _ sceneGraphListeners class table.

In the EventToListener processing of the _ fixedListeners class table, if the priority is less than 0, the processing method is not executed; the processing method of EventToListener is an anonymous function passed through the parameter; the implementation of this anonymous function will be further described below

4. The onTouchEvent method in the dispatchTouchEvent Method

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;};
  
 

In the onTouchEvent anonymous method:

(1) Forcibly convert the passed parameter to the EventListenerTouchOneByOne type and determine whether it is null.

(2) obtain the Event type of the touch (Win32 mouse click \ drag ).

(3) when determining whether the Event type is

A) call the onTouchBegan specified by EventListener at registration and obtain the returned value.

B) if the return value is true, put the Touch information of the Event into _ claimedTouches.

(4) when determining whether the Event type is not

A) The content of _ claimedTouches is not empty. The Touch information of this Event is displayed in _ claimedTouches.

B) if the Event type is MOVED, call the onTouchMoved specified by EventListener at registration.

C) if the Event type is ENDED, call the onTouchEnded

D) if the Event type is CANCELLED, call the onTouchCancelled specified by EventListener at registration.

E) Remove the Touch information of the Event from _ claimedTouches.

(5) If the Event is stopped, update the EventListener list.

(6) If onTouchBegan returns true and _ needSwallow is set to true, the current Event will be removed from the multi-touch Event list.

In this anonymous method, the onTouchBegan return value is very important. It focuses on whether other subsequent touch operations (onTouchMoved \ onTouchEnded \ onTouchCancelled) are executed. If so, the _ needSwallow flag takes effect;

5. The onTouchEvent anonymous method of multiple points in the dispatchTouchEvent Method

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;};
 

In the onTouchEvent anonymous method:

(1) Forcibly convert the passed parameter to the EventListenerTouchAllAtOnce type and determine whether it is null.

(2) obtain the Event type of the touch (Win32 mouse click \ drag ).

(3) If the Event type is BEGAN, call the onTouchBegan method specified by EventListener at registration.

(4) If the Event type is MOVED, call the onTouchesMoved method specified by EventListener at registration.

(5) If the Event type is ENDED, call the onTouchesEnded method specified by EventListener at registration.

(6) If the Event type is CANCELLED, call the onTouchesCancelled method specified by EventListener at registration.

(7) If the Event is stopped, update the EventListener list.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.