• Cocos2dx之touch事件


    今天看了下ccocos2dx touch事件部分的源码,从CCTouch、CCTouchHandler和CCTouchDispatcher简单的做了分析和总结,先直接看源码吧!

    1、CCTouch

    class CC_DLL CCTouch : public CCObject
    {
    public:
        CCTouch() 
            : m_nId(0),
            m_startPointCaptured(false)
        {}
    
        /** returns the current touch location in OpenGL coordinates */
        CCPoint getLocation() const;//获取当前touch位置,该位置基于OpenGL坐标
        /** returns the previous touch location in OpenGL coordinates */
        CCPoint getPreviousLocation() const;//获取前一次touch位置,该位置基于OpenGL坐标
        /** returns the start touch location in OpenGL coordinates */
        CCPoint getStartLocation() const;//获取该touch的起始位置,该位置基于OpenGL坐标
        /** returns the delta of 2 current touches locations in screen coordinates */
        CCPoint getDelta() const;  //获取前后两次位置的偏移量,基于OpenGL坐标
        /** returns the current touch location in screen coordinates */
        CCPoint getLocationInView() const; //当前touch位置,该位置基于屏幕坐标位置
        /** returns the previous touch location in screen coordinates */
        CCPoint getPreviousLocationInView() const; //获取touch前一次的位置,基于屏幕坐标位置
        /** returns the start touch location in screen coordinates */
        CCPoint getStartLocationInView() const;  //获取touch起始位置,基于屏幕坐标位置
        
        void setTouchInfo(int id, float x, float y)
        {
            m_nId = id;
            m_prevPoint = m_point;
            m_point.x   = x;
            m_point.y   = y;
            if (!m_startPointCaptured)
            {
                m_startPoint = m_point;
                m_startPointCaptured = true;
            }
        }
    
        int getID() const
        {
            return m_nId;
        }
    
    private:
        int m_nId;
        bool m_startPointCaptured;
        CCPoint m_startPoint;
        CCPoint m_point;
        CCPoint m_prevPoint;
    };

    CCTouch中有三个主要成员,m_startPoint、m_point、m_prevPoint,这三个点都是基于屏幕坐标。将这三个点转化为OpenGL坐标可以用CCDirector::sharedDirector()->convertToGL(m_point)函数来转化。

    2、CCTouchHandler、CCStandardTouchHandler和CCTargetedTouchHandler

    class CC_DLL  CCTouchHandler : public CCObject
    {
    public:
        virtual ~CCTouchHandler(void);
    
        /** delegate */
        CCTouchDelegate* getDelegate();    //获取touch代理
        void setDelegate(CCTouchDelegate *pDelegate); //设置touch代理
    
        /** priority */
        int getPriority(void);    //获取代理优先级
        void setPriority(int nPriority); //获取代理优先级
    
        /** enabled selectors */
        int getEnabledSelectors(void); //
        void setEnalbedSelectors(int nValue);
    
        /** initializes a TouchHandler with a delegate and a priority */
        virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority);
    
    public:
        /** allocates a TouchHandler with a delegate and a priority *///创建一个CCTouchHandler
    static CCTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);
    
    protected:
        CCTouchDelegate *m_pDelegate;     //touch代理
        int m_nPriority;            //优先级
        int m_nEnabledSelectors;      //该成员没看出来有什么作用
    };
    CCTouchHandler主要将touch代理和优先级封装起来,CCTouchHandler还有两个派生对象: CCStandardTouchHandler和CCTargetedTouchHandler。这两个派生类很简单不需多说,简单的贴上代码吧。
    class CC_DLL  CCStandardTouchHandler : public CCTouchHandler
    {
    public:
        /** initializes a TouchHandler with a delegate and a priority */
        virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority);
    
    public:
        /** allocates a TouchHandler with a delegate and a priority */
        static CCStandardTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);
    };
    class CC_DLL  CCTargetedTouchHandler : public CCTouchHandler
    {
    public:
        ~CCTargetedTouchHandler(void);
    
        /** whether or not the touches are swallowed */
        bool isSwallowsTouches(void);        //是否吞掉CCTouch
        void setSwallowsTouches(bool bSwallowsTouches);  //设置是否吞掉CCTouch
    
        /** MutableSet that contains the claimed touches */
        CCSet* getClaimedTouches(void);          //获取将要处理的CCTouch的集合
    
        /** initializes a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */
        bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow);
    
    public:
        /** allocates a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */
        static CCTargetedTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow);
    
    protected:
        bool m_bSwallowsTouches;      //处理CCTouch后是否吞掉该CCTouch
        CCSet *m_pClaimedTouches;     //要处理的CCTouch集合
    };

    3、CCTouch事件分发器CCTouchDispatcher

    class CC_DLL CCTouchDispatcher : public CCObject, public EGLTouchDelegate
    {
    public:
        ~CCTouchDispatcher();
        bool init(void);
        CCTouchDispatcher() 
            : m_pTargetedHandlers(NULL)
            , m_pStandardHandlers(NULL)
            , m_pHandlersToAdd(NULL)
            , m_pHandlersToRemove(NULL)
            
        {}
    
    public:
        /** Whether or not the events are going to be dispatched. Default: true */
        bool isDispatchEvents(void);           //事件是否要被分发
        void setDispatchEvents(bool bDispatchEvents);  //设置是否分发事件
    
        /** Adds a standard touch delegate to the dispatcher's list.
         See StandardTouchDelegate description.
         IMPORTANT: The delegate will be retained.
         */
        void addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority);    //向标准代理容器添加代理
    
        /** Adds a targeted touch delegate to the dispatcher's list.
         See TargetedTouchDelegate description.
         IMPORTANT: The delegate will be retained.
         */
        void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches); //向目标代理容器添加代理
    
        /** Removes a touch delegate.
         The delegate will be released
         */
        void removeDelegate(CCTouchDelegate *pDelegate);//移除特定代理
    
        /** Removes all touch delegates, releasing all the delegates */
        void removeAllDelegates(void);//移除所有代理
    
        /** Changes the priority of a previously added delegate. The lower the number,
        the higher the priority */
        void setPriority(int nPriority, CCTouchDelegate *pDelegate);//设置特定代理的优先级
    
        void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex);  //分发事件逻辑处理,主要看的函数
        //以下是对四种事件的处理
        virtual void touchesBegan(CCSet* touches, CCEvent* pEvent);
        virtual void touchesMoved(CCSet* touches, CCEvent* pEvent);
        virtual void touchesEnded(CCSet* touches, CCEvent* pEvent);
        virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent);
    
    public:
        CCTouchHandler* findHandler(CCTouchDelegate *pDelegate);  //根据代理查找特定CCTouchHandler
    protected:
        void forceRemoveDelegate(CCTouchDelegate *pDelegate);
        void forceAddHandler(CCTouchHandler *pHandler, CCArray* pArray);
        void forceRemoveAllDelegates(void);
        void rearrangeHandlers(CCArray* pArray);      //重新根据优先级对代理排序
        CCTouchHandler* findHandler(CCArray* pArray, CCTouchDelegate *pDelegate);
    
    protected:
         CCArray* m_pTargetedHandlers;     //目标事件代理容器
         CCArray* m_pStandardHandlers;     //标准事件代理容器
    
        bool m_bLocked;      //是否被锁
        bool m_bToAdd;      //是否需要添加
        bool m_bToRemove;   //是否需要删除
         CCArray* m_pHandlersToAdd; //要添加的代理容器
        struct _ccCArray *m_pHandlersToRemove; //要删除的代理容器
        bool m_bToQuit;     //是否要退出
        bool m_bDispatchEvents;  //是否要处理touch事件
    
        // 4, 1 for each type of event
        struct ccTouchHandlerHelperData m_sHandlerHelperData[ccTouchMax];
    };

    我们主要看一看void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex); 这个函数看看touch事件分发器是如何实现事件的分发。先贴上该函数源码

    void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex)
    {
        CCAssert(uIndex >= 0 && uIndex < 4, "");   //检查4种touch事件的类型
    
        CCSet *pMutableTouches;
        m_bLocked = true;                      //正在进行事件分发的时候先锁定,避免代理容器内部发生变化
    
        // optimization to prevent a mutable copy when it is not necessary
         unsigned int uTargetedHandlersCount = m_pTargetedHandlers->count();    //获取目标事件代理个数
         unsigned int uStandardHandlersCount = m_pStandardHandlers->count();    //获取标准事件代理个数
        bool bNeedsMutableSet = (uTargetedHandlersCount && uStandardHandlersCount); //需不需要拷贝CCTouch容器
    
        pMutableTouches = (bNeedsMutableSet ? pTouches->mutableCopy() : pTouches);   //拷贝CCTouch容器用于向标准touch代理分发事件
    
        struct ccTouchHandlerHelperData sHelper = m_sHandlerHelperData[uIndex];
        //
        // process the target handlers 1st
        //
        if (uTargetedHandlersCount > 0)
        {
            CCTouch *pTouch;
            CCSetIterator setIter;
            for (setIter = pTouches->begin(); setIter != pTouches->end(); ++setIter)     //遍历CCTouch集合
            {
                pTouch = (CCTouch *)(*setIter);
    
                CCTargetedTouchHandler *pHandler = NULL;
                CCObject* pObj = NULL;
                CCARRAY_FOREACH(m_pTargetedHandlers, pObj)     //对于每一个CCTouch,遍历每一个目标事件代理处理器
                {
                    pHandler = (CCTargetedTouchHandler *)(pObj);  
    
                    if (! pHandler)
                    {
                       break;
                    }
    
                    bool bClaimed = false;        //是否要得到处理
                    if (uIndex == CCTOUCHBEGAN)
                    {
                        bClaimed=pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent);//调用代理的ccTouchBegan函数
                        if (bClaimed)    //如果ccTouchBegan函数返回true,说明事件要被处理
                        {
                            pHandler->getClaimedTouches()->addObject(pTouch);   //将该touch事件加入到该touch事件处理器的待处理事件容器中
                        }
                    } else
                    if (pHandler->getClaimedTouches()->containsObject(pTouch))     //判断handler内是否有该CCTouch
                    {
                        // moved ended canceled
                        bClaimed = true;       //标记要被处理
    
                        switch (sHelper.m_type)
                        {
                        case CCTOUCHMOVED:
                            pHandler->getDelegate()->ccTouchMoved(pTouch, pEvent);   //注意处理CCTouchMoved 不会移除相应CCTouch
                            break;
                        case CCTOUCHENDED:
                            pHandler->getDelegate()->ccTouchEnded(pTouch, pEvent);
                            pHandler->getClaimedTouches()->removeObject(pTouch);     //从代理handler中的要处理的CCTouch容器中移除该CCTouch
                            break;
                        case CCTOUCHCANCELLED:
                            pHandler->getDelegate()->ccTouchCancelled(pTouch, pEvent);
                            pHandler->getClaimedTouches()->removeObject(pTouch);     //从代理handler中的要处理的CCTouch容器中移除该CCTouch
                            break;
                        }
                    }
    
                    if (bClaimed && pHandler->isSwallowsTouches())   //已经被处理并且要吞掉
                    {
                        if (bNeedsMutableSet)     //
                        {
                            pMutableTouches->removeObject(pTouch);   //从用于向标准代理分发事件的容器中移除该CCTouch
                        }
    
                        break;
                    }
                }
            }
        }
    
        //
        // process standard handlers 2nd
        //处理标准事件的分发,比目标事件简单
        if (uStandardHandlersCount > 0 && pMutableTouches->count() > 0)
        {
            CCStandardTouchHandler *pHandler = NULL;
            CCObject* pObj = NULL;
            CCARRAY_FOREACH(m_pStandardHandlers, pObj)
            {
                pHandler = (CCStandardTouchHandler*)(pObj);
    
                if (! pHandler)
                {
                    break;
                }
    
                switch (sHelper.m_type)
                {
                case CCTOUCHBEGAN:
                    pHandler->getDelegate()->ccTouchesBegan(pMutableTouches, pEvent);
                    break;
                case CCTOUCHMOVED:
                    pHandler->getDelegate()->ccTouchesMoved(pMutableTouches, pEvent);
                    break;
                case CCTOUCHENDED:
                    pHandler->getDelegate()->ccTouchesEnded(pMutableTouches, pEvent);
                    break;
                case CCTOUCHCANCELLED:
                    pHandler->getDelegate()->ccTouchesCancelled(pMutableTouches, pEvent);
                    break;
                }
            }
        }
    
        if (bNeedsMutableSet)  
        {
            pMutableTouches->release();   //释放掉拷贝过来用于分发标准事件的touch集合
        }
    
        //
        // Optimization. To prevent a [handlers copy] which is expensive
        // the add/removes/quit is done after the iterations
        //
        m_bLocked = false;    //解除锁定
        if (m_bToRemove)    //有需要被移除的代理
        {
            m_bToRemove = false;
            for (unsigned int i = 0; i < m_pHandlersToRemove->num; ++i)
            {
                forceRemoveDelegate((CCTouchDelegate*)m_pHandlersToRemove->arr[i]);
            }
            ccCArrayRemoveAllValues(m_pHandlersToRemove);
        }
    
        if (m_bToAdd)   //有需要被添加的代理
        {
            m_bToAdd = false;
            CCTouchHandler* pHandler = NULL;
            CCObject* pObj = NULL;
            CCARRAY_FOREACH(m_pHandlersToAdd, pObj)
             {
                 pHandler = (CCTouchHandler*)pObj;
                if (! pHandler)
                {
                    break;
                }
    
                if (dynamic_cast<CCTargetedTouchHandler*>(pHandler) != NULL)
                {                
                    forceAddHandler(pHandler, m_pTargetedHandlers);
                }
                else
                {
                    forceAddHandler(pHandler, m_pStandardHandlers);
                }
             }
     
             m_pHandlersToAdd->removeAllObjects();    
        }
    
        if (m_bToQuit)   //需要退出
        {
            m_bToQuit = false;
            forceRemoveAllDelegates();    //删除所有代理
        }
    }

      从代码中我们可以清楚的看到时间分发的逻辑,cocos2dx将代理分为两种类型:标准事件代理和目标事件代理,事件分发的时候分别处理;事件分为四种事件,CCTOUCHBEGAN、CCTOUCHMOVED、CCTOUCHENDED和CCTOUCHCANCELLED;当调用目标代理的ccTouchBegan函数返回为真说明改代理需要处理该事件,并将该事件暂存到CCTargetedTouchHandler得集合中,当调用ccTouchMoved、ccTouchEnded和ccTouchCanceled时若该代理是否要吞掉该事件则删除标准容器中的该事件。标准事件的分发比较简单略过,还有一点就是,cocos2dx在进行事件分发的时候,将两种容器锁定,避免分发事件的时候容器中的代理有变化,事件分发结束后再将该添加的代理添加,该删除的代理删除。

    4、CCTouch、CCTouchHandler和CCTouchDispatcher之间的关系如下图所示:

  • 相关阅读:
    如何禁止用户直接对TextBox进行数据粘贴?(ASP.NET WEB开发)
    jquery过滤选择器前加空格与不加空格的区别(转)
    linux设置ip.dns.gateway
    Adobe Fireworks CS4 序列号(注册码)
    AS3清空数组的四种方法
    Flash中用AS3做的游戏,导出apk安装到手机上滤镜效果出不来为什么?
    用AS3清空容器下所有子显示对象
    对Linux进程的理解
    C++基础
    虚拟机三种网络模式(hostonly、Bridged、NAT)
  • 原文地址:https://www.cnblogs.com/yu-chao/p/3820593.html
Copyright © 2020-2023  润新知