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之间的关系如下图所示:

Cocos2dx之touch事件,布布扣,bubuko.com

时间: 2024-10-13 12:37:07

Cocos2dx之touch事件的相关文章

cocos2dx 3.1从零学习(三)——Touch事件(回调,反向传值)

第三讲 Touch 前面两篇我们学习的内容,足够我们做一款简单的小游戏.也可以说,我们已经入门了,可以蹒跚的走路了. 本篇将讲解cocos2dx中很重要的touch回调机制.你肯定记得第一章做定时器时间的时候用过CC_CALLBACK_1宏定义,它让我们回调一个只有一个形参的函数来执行定时操作. 回调函数的实现(Lambda表达式) 学习本篇前请仔细学习一下C++11的特性,std::function和lambda表达式.C++11还引入了很多boost库的优秀代码,使我们在使用的时候不必再加b

cocos2d-x中关于touch事件的响应

原作者:有缘人  来源:新浪微博 地址:http://blog.sina.com.cn/s/blog_6ac2c7260102vvdu.html 一.touch事件响应分为单点触摸响应和多点触摸响应. 单点触摸响应需要重载的方法: virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); virtual void

Cocos2d-x中触摸事件

理解一个触摸事件可以从时间和空间两方面考虑. 1.触摸事件的时间方面 触摸事件的在时间方面,如下图所示,可以有不同的"按下"."移动"和"抬起"等阶段,表示触摸是否刚刚开始.是否正在移动或处于静止状态,以及何时结束,也就是手指何时从屏幕抬起.此外,触摸事件的不同阶段都可以有单点触摸或多点触摸,是否支持多点触摸还要看设备和平台. 触摸事件有两个事件监听器:EventListenerTouchOneByOne和EventListenerTouchAl

Cocos2d-x 3.X 事件分发机制

介绍 Cocos2d-X 3.X 引入了一种新的响应用户事件的机制. 涉及三个基本的方面: Event listeners 封装你的事件处理代码 Event dispatcher 向 listener 分发用户事件 Event 对象 包含关于事件的信息 为了响应事件,首先你要创建一个 EventListener,有五种不同的 EventListener. EventListenerTouch 响应触控事件 EventListenerKeyboard 响应键盘事件 EventListenerAcc

CCLayer在Touch事件(Standard Touch Delegate和Targeted Touch Delegate)

在做练习,触摸故障,看到源代码,以了解下触摸事件. 练习操作:直CClayer子类init在 this->setTouchEnabled(true); 事件处理方法覆盖 virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event); virtual void ccTouchMoved(CCTouch* touch, CCEvent* event); virtual void ccTouchEnded(CCTouch* touch, CCEve

cocos2d-x 3.0 事件分发机制

在cocos2d-x 3.0中一共有五个事件监听器: 触摸事件(EventListenerTouch) 键盘响应事件 (EventListenerKeyboard) 加速器记录事件(EventListenerAcceleration) 鼠标响应事件(EventListenerMouse) 自定义事件(EventListenerCustom) 顾名思义,就是分别监听touch,key.加速器.mouse和自定义的事情. 对于加速器记录事件,现在基本上没有接触到这方面,就先略过吧... 触摸事件:

cocos2dx 3.2 事件机制

一个sprite的情况 // oneSprite void HelloWorld::touchableSpriteTestOne() { Vec2 origin = Director::getInstance()->getVisibleOrigin(); Size size = Director::getInstance()->getVisibleSize(); auto sprite1 = Sprite::create("Images/CyanSquare.png");

cocos2dx 点击事件分析(3)

1.在cocos2dx 点击事件分析(2)中,我们已经从java端分析了,单手触摸和多手触摸屏幕. num --- 1,不论单点触摸还是多点触摸,这个值都是1 ids[] --- 触摸事件的ID void CCEGLViewProtocol::handleTouchesBegin(int num, int ids[], float xs[], float ys[]) { CCSet set; for (int i = 0; i < num; ++i) { int id = ids[i]; flo

Android的Touch事件分发机制简单探析

前言 Android中关于触摸事件的分发传递是一个很值得研究的东西.曾不见你引入了一个ListView的滑动功能,ListView就不听你手指的指唤来滚动了:也不知道为啥Button设置了onClick和onTouch,其中谁会先响应:或许你会问onTouch和onTouchEvent有什么区别,又该如何使用?这里一切的一切,只要你了解了事件分发机制,你会发现,解释这都不是事儿! 相关Touch事件的方法 1.public boolean dispatchTouchEvent(MotionEve