cocos2d-x触摸事件详细分析

本文详细解析了Cocos2d-x在启动时如何初始化CCEGLView和导演,以及如何处理触摸事件。重点阐述了触摸事件的创建、触发流程、处理方式以及触摸分发事件的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在cocos2d-x启动时会初始化CCEGLView(不同平台,都有自己的实现,由于自己是在win32平台下开发,所以这里的CCEGLView实现是win32下的)。

int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow)
{
    ...
    CCEGLView* eglView = CCEGLView::sharedOpenGLView();
    ...
}
然后再初始化导演时会把它设置进去

bool AppDelegate::applicationDidFinishLaunching() {
    ...
    CCDirector* pDirector = CCDirector::sharedDirector();
    CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();
    ...
}
另外在初始化导演时也会做另一件重要的事情——创建触摸分发事件(往下还有键盘和重力感应事件,这里只说触摸事件):

bool CCDirector::init(void)
{
	...
    m_pTouchDispatcher = new CCTouchDispatcher();
    m_pTouchDispatcher->init();
    ...

    return true;
}
这样便完成了游戏的触摸分发的创建。


接下来看什么时候会触发这个事件。

触发时会按以下流程来完成:

1)在创建CCEGLView时会初始化窗口信息,包括事件的处理

CCEGLView* CCEGLView::sharedOpenGLView()
{
  
    if (s_pEglView == NULL)
    {
        s_pEglView = new CCEGLView();
		if(!s_pEglView->Create())//初始化窗口信息
		{
			delete s_pEglView;
			s_pEglView = NULL;
		}
    }

    return s_pEglView;
}
bool CCEGLView::Create()
{
   ...
	wc.lpfnWndProc    = _WindowProc;                    // WndProc Handles Messages
	...

    return bRet;
}
上面的那个消息便是我们要的内容。
static LRESULT CALLBACK _WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    ...
        return s_pMainWindow->WindowProc(uMsg, wParam, lParam);
    ...
}
LRESULT CCEGLView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    BOOL bProcessed = FALSE;

    switch (message)
    {
    case WM_LBUTTONDOWN://鼠标左键按下
#if(_MSC_VER >= 1600)
        // Don't process message generated by Windows Touch
        if (m_bSupportTouch && (s_pfGetMessageExtraInfoFunction() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) break;
#endif /* #if(_MSC_VER >= 1600) */

        if (m_pDelegate && MK_LBUTTON == wParam)
        {
            POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
            CCPoint pt(point.x, point.y);
            pt.x /= m_fFrameZoomFactor;
            pt.y /= m_fFrameZoomFactor;
            CCPoint tmp = ccp(pt.x, m_obScreenSize.height - pt.y);//得到触摸点
            if (m_obViewPortRect.equals(CCRectZero) || m_obViewPortRect.containsPoint(tmp))
            {
                m_bCaptured = true;//只有按下鼠标的左键后后面的事件才会继续被捕捉
                SetCapture(m_hWnd);
                int id = 0;
                handleTouchesBegin(1, &id, &pt.x, &pt.y);//处理CCTouchBegin事件
            }
        }
        break;

    case WM_MOUSEMOVE://鼠标左键按下并移动
#if(_MSC_VER >= 1600)
        // Don't process message generated by Windows Touch
        if (m_bSupportTouch && (s_pfGetMessageExtraInfoFunction() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) break;
#endif /* #if(_MSC_VER >= 1600) */
        if (MK_LBUTTON == wParam && m_bCaptured)
        {
            POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
            CCPoint pt(point.x, point.y);
            int id = 0;
            pt.x /= m_fFrameZoomFactor;
            pt.y /= m_fFrameZoomFactor;
            handleTouchesMove(1, &id, &pt.x, &pt.y);//处理CCTouchMove事件
        }
        break;

    case WM_LBUTTONUP://鼠标左键抬起
#if(_MSC_VER >= 1600)
        // Don't process message generated by Windows Touch
        if (m_bSupportTouch && (s_pfGetMessageExtraInfoFunction() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) break;
#endif /* #if(_MSC_VER >= 1600) */
        if (m_bCaptured)
        {
            POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
            CCPoint pt(point.x, point.y);
            int id = 0;
            pt.x /= m_fFrameZoomFactor;
            pt.y /= m_fFrameZoomFactor;
            handleTouchesEnd(1, &id, &pt.x, &pt.y);//处理CCTouchEnd事件

            ReleaseCapture();
            m_bCaptured = false;//捕捉结束
        }
        break;
    ...
    //处理其他事件,如键盘,和后续操作
    return 0;
}
到这里就很明显的可以看出在win32平台就是用鼠标的左键来模拟触摸的。其中,对应的三个触摸事件的声明和实现被放在它的父类中去实现,也就是CCEGLViewProtocol

class CC_DLL CCEGLView : public CCEGLViewProtocol
因为它与平台无关,即CCEGLview实现不同平台的不同的触摸处理,而CCEGLViewProtocol则定义了这些行为而已,而这些行为统一由cocos2d-x,这样便能大大的降低引擎与平台的耦合度。


综合上面也内容可以看出cocos2d-x在启动时会初始化导演,并设置CCEGLView,而CCEGLiew的父类CCEGLViewProtocol则定义了触摸的行为方法,所以在设置CCEGLView时就已经悄悄的把这些行为与导演绑定在一起了,而且初始化导演时也已经创建了能触摸分发事件的句柄。

bool AppDelegate::applicationDidFinishLaunching() {
    ...

    pDirector->setOpenGLView(pEGLView);
	
    ...
}
void CCDirector::setOpenGLView(CCEGLView *pobOpenGLView)
{
    ...
        m_pobOpenGLView->setTouchDelegate(m_pTouchDispatcher);
        m_pTouchDispatcher->setDispatchEvents(true);//设置触摸事件为true,这里要一定要设置为true,不然所有事件都失效
    ...
}
这样在CCEGLViewProtocol中便能用m_pTouchDispatcher来操作触摸分发事件了。

void CCEGLViewProtocol::handleTouchesBegin(int num, int ids[], float xs[], float ys[])
{
	//计算触摸点集合set
    ...

    m_pDelegate->touchesBegan(&set, NULL);
}

void CCEGLViewProtocol::handleTouchesMove(int num, int ids[], float xs[], float ys[])
{
	//计算触摸点集合set
    ...

    m_pDelegate->touchesMoved(&set, NULL);
}

void CCEGLViewProtocol::handleTouchesEnd(int num, int ids[], float xs[], float ys[])
{
	//计算触摸点集合set
    ...
    
    m_pDelegate->touchesEnded(&set, NULL);
}

void CCEGLViewProtocol::handleTouchesCancel(int num, int ids[], float xs[], float ys[])
{
	//计算触摸点集合set
    ...
    
    m_pDelegate->touchesCancelled(&set, NULL);
}
可以看到这些事件的处理的第二个参数都是NULL,也就是说是个无用参数(之所以这个无用的参数据说是cocos2d-iphone遗留下来的)。

接下来看触摸分发类的对这些方法的定义,这些定义是在它的父类中,即触摸事件委托类EGLTouchDelegate:

class CC_DLL EGLTouchDelegate//触摸事件委托
{
public:
    /**
     * @lua NA
     */
    virtual void touchesBegan(CCSet* touches, CCEvent* pEvent) = 0;//触摸被按下
    /**
     * @lua NA
     */
    virtual void touchesMoved(CCSet* touches, CCEvent* pEvent) = 0;//触摸移动
    /**
     * @lua NA
     */
    virtual void touchesEnded(CCSet* touches, CCEvent* pEvent) = 0;//触摸结束
    /**
     * @lua NA
     */
    virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent) = 0;//当系统被通知需要取消触摸事件才会触发它,一般不用它
    /**
     * @lua NA
     */
    virtual ~EGLTouchDelegate() {}//析构
};

class CC_DLL CCTouchDispatcher : public CCObject, public EGLTouchDelegate
{
public:
    /**
     * @lua NA
     */
	//析构
    ~CCTouchDispatcher();
    /**
     * @lua NA
     */
    //初始化
    bool init(void);
    /**
     * @lua NA
     */
    //构造
    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.
     * @lua NA
     */
    //注册标准触摸事件
    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.
     * @lua NA
     */
    //注册目标触摸事件
    void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches);

    /** Removes a touch delegate.
     * The delegate will be released
     * @lua NA
     */
    //移除指定触摸事件
    void removeDelegate(CCTouchDelegate *pDelegate);

    /** Removes all touch delegates, releasing all the delegates 
     * @lua NA
     */
    //移除所有触摸事件
    void removeAllDelegates(void);

    /** Changes the priority of a previously added delegate. The lower the number,
     * the higher the priority 
     * @lua NA
     */
    //设置触摸优先级
    void setPriority(int nPriority, CCTouchDelegate *pDelegate);
    /**
     * @lua NA
     */
    //触摸操作
    void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex);

    //重写父类方法
    /**
     * @lua NA
     */
    virtual void touchesBegan(CCSet* touches, CCEvent* pEvent);
    /**
     * @lua NA
     */
    virtual void touchesMoved(CCSet* touches, CCEvent* pEvent);
    /**
     * @lua NA
     */
    virtual void touchesEnded(CCSet* touches, CCEvent* pEvent);
    /**
     * @lua NA
     */
    virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent);

public:
    /**
     * @lua NA
     */
    //触摸句柄,握有触摸的优先级
    CCTouchHandler* findHandler(CCTouchDelegate *pDelegate);
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;//是否分发事件,false不分发

    // 4, 1 for each type of event
    struct ccTouchHandlerHelperData m_sHandlerHelperData[ccTouchMax];//操作类别,辅助用
};

在cocos2d-x中,有两种触摸事件类型,分别是标准触摸事件和带目标触摸事件,这个两个事件在分发是分别存在各自的触摸句柄类的数组中。

触摸句柄:

//触摸事件句柄
class CC_DLL  CCTouchHandler : public CCObject
{
public:
    virtual ~CCTouchHandler(void);//析构

    /** delegate */
    CCTouchDelegate* getDelegate();//获取触摸事件委托
    void setDelegate(CCTouchDelegate *pDelegate);//设置触摸事件委托

    /** 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 */
    static CCTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);//创建触摸句柄类

protected:
    CCTouchDelegate *m_pDelegate;//触摸事件委托
    int m_nPriority;//优先级
    int m_nEnabledSelectors;//不知何用???
};

//标准触摸事件句柄
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);//获取是否吞噬分发
    void setSwallowsTouches(bool bSwallowsTouches);//设置是否吞噬分发

    /** MutableSet that contains the claimed touches */
    CCSet* getClaimedTouches(void);//存储用于声明的触摸事件

    /** 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;
    CCSet *m_pClaimedTouches;
};

CCTouchDelegate* CCTouchHandler::getDelegate(void)
{
    return m_pDelegate;//返回触摸委托
}

void CCTouchHandler::setDelegate(CCTouchDelegate *pDelegate)
{
    if (pDelegate)//传进来的委托不为空
    {
        dynamic_cast<CCObject*>(pDelegate)->retain();//引用计数加1
    }

    if (m_pDelegate)//如果之前设置过委托,释放掉它
    {
        dynamic_cast<CCObject*>(m_pDelegate)->release();
    }

    m_pDelegate = pDelegate;//设置新的委托
}

int CCTouchHandler::getPriority(void)
{
    return m_nPriority;//返回优先级
}

void CCTouchHandler::setPriority(int nPriority)
{
    m_nPriority = nPriority;//设置优先级
}

int CCTouchHandler::getEnabledSelectors(void)
{
    return m_nEnabledSelectors;
}

void CCTouchHandler::setEnalbedSelectors(int nValue)
{
    m_nEnabledSelectors = nValue;
}

CCTouchHandler* CCTouchHandler::handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority)
{
    CCTouchHandler *pHandler = new CCTouchHandler();//创建新的触摸句柄

    if (pHandler)
    {
        if (pHandler->initWithDelegate(pDelegate, nPriority))//初始化
        {
            pHandler->autorelease();//放入内存回收池
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pHandler);
        }
    }
    
    return pHandler;
}

bool CCTouchHandler::initWithDelegate(CCTouchDelegate *pDelegate, int nPriority)
{
    CCAssert(pDelegate != NULL, "touch delegate should not be null");

    m_pDelegate = pDelegate; //设置委托

    dynamic_cast<CCObject*>(pDelegate)->retain();//引用计数加1

    m_nPriority = nPriority;//设置优先级
    m_nEnabledSelectors = 0;

    return true;
}

CCTouchHandler::~CCTouchHandler(void)
{
    if (m_pDelegate)//释放掉触摸委托资源
    {
        dynamic_cast<CCObject*>(m_pDelegate)->release();
    }   
}

// implementation of CCStandardTouchHandler
bool CCStandardTouchHandler::initWithDelegate(CCTouchDelegate *pDelegate, int nPriority)
{
    if (CCTouchHandler::initWithDelegate(pDelegate, nPriority))//初始化
    {
        return true;
    }

    return false;
}

CCStandardTouchHandler* CCStandardTouchHandler::handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority)
{
    CCStandardTouchHandler* pHandler = new CCStandardTouchHandler();

    if (pHandler)
    {
        if (pHandler->initWithDelegate(pDelegate, nPriority))//初始化
        {
            pHandler->autorelease();//放入内存回收池
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pHandler);
        }
    }

    return pHandler;
}

// implementation of CCTargetedTouchHandler

bool CCTargetedTouchHandler::isSwallowsTouches(void)
{
    return m_bSwallowsTouches;//返回是否吞噬事件
}

void CCTargetedTouchHandler::setSwallowsTouches(bool bSwallowsTouches)
{
    m_bSwallowsTouches = bSwallowsTouches;//设置是否吞噬事件
}

CCSet* CCTargetedTouchHandler::getClaimedTouches(void)
{
    return m_pClaimedTouches;//返回声明触摸事件容器
}

CCTargetedTouchHandler* CCTargetedTouchHandler::handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow)
{
    CCTargetedTouchHandler *pHandler = new CCTargetedTouchHandler();
    if (pHandler)
    {
        if (pHandler->initWithDelegate(pDelegate, nPriority, bSwallow))//初始化
        {
            pHandler->autorelease();//放入内存回收池
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pHandler);
        }
    }

    return pHandler;
}

bool CCTargetedTouchHandler::initWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow)
{
    if (CCTouchHandler::initWithDelegate(pDelegate, nPriority))//初始化
    {
        m_pClaimedTouches = new CCSet();
        m_bSwallowsTouches = bSwallow;

        return true;
    }

    return false;
}

CCTargetedTouchHandler::~CCTargetedTouchHandler(void)
{
    CC_SAFE_RELEASE(m_pClaimedTouches);//释放资源
}
最后便是触摸分发事件的实现了:

static int less(const CCObject* p1, const CCObject* p2)
{
    return ((CCTouchHandler*)p1)->getPriority() < ((CCTouchHandler*)p2)->getPriority();//判断两个参数间的优先级大小,排序用
}

bool CCTouchDispatcher::isDispatchEvents(void)
{
    return m_bDispatchEvents;//返回触摸事件是否分发
}

void CCTouchDispatcher::setDispatchEvents(bool bDispatchEvents)
{
    m_bDispatchEvents = bDispatchEvents;//设置触摸事件是否分发
}

/*
+(id) allocWithZone:(CCZone *)zone
{
    @synchronized(self) {
        CCAssert(sharedDispatcher == nil, @"Attempted to allocate a second instance of a singleton.");
        return [super allocWithZone:zone];
    }
    return nil; // on subsequent allocation attempts return nil
}
*/

bool CCTouchDispatcher::init(void)
{
    m_bDispatchEvents = true;//默认情况下设置触摸事件分发
    //初始化目标触摸事件的容器
    m_pTargetedHandlers = CCArray::createWithCapacity(8);
    m_pTargetedHandlers->retain();
    //初始化标准触摸事件的容器
     m_pStandardHandlers = CCArray::createWithCapacity(4);
    m_pStandardHandlers->retain();
    //初始化待分发触摸事件的缓冲容器
    m_pHandlersToAdd = CCArray::createWithCapacity(8);
    m_pHandlersToAdd->retain();
    //初始化待移除触摸事件的缓冲容器
    m_pHandlersToRemove = ccCArrayNew(8);
    
    //初始化其他属性
    m_bToRemove = false;
    m_bToAdd = false;
    m_bToQuit = false;
    m_bLocked = false;
    //初始化触摸操作类型
    m_sHandlerHelperData[CCTOUCHBEGAN].m_type = CCTOUCHBEGAN;
    m_sHandlerHelperData[CCTOUCHMOVED].m_type = CCTOUCHMOVED;
    m_sHandlerHelperData[CCTOUCHENDED].m_type = CCTOUCHENDED;
    m_sHandlerHelperData[CCTOUCHCANCELLED].m_type = CCTOUCHCANCELLED;

    return true;
}

CCTouchDispatcher::~CCTouchDispatcher(void)
{
	//释放所用的容器的资源
     CC_SAFE_RELEASE(m_pTargetedHandlers);
     CC_SAFE_RELEASE(m_pStandardHandlers);
     CC_SAFE_RELEASE(m_pHandlersToAdd);
 
     ccCArrayFree(m_pHandlersToRemove);
    m_pHandlersToRemove = NULL;    
}

//
// handlers management
//
void CCTouchDispatcher::forceAddHandler(CCTouchHandler *pHandler, CCArray *pArray)
{
    unsigned int u = 0;

    CCObject* pObj = NULL;
    //计算插入位置u
    CCARRAY_FOREACH(pArray, pObj)
     {
         CCTouchHandler *h = (CCTouchHandler *)pObj;
         if (h)
         {
             if (h->getPriority() < pHandler->getPriority())
             {
                 ++u;
             }
 
             if (h->getDelegate() == pHandler->getDelegate())//如果已存在容器,返回
             {
                 CCAssert(0, "");
                 return;
             }
         }
     }
    //插入
    pArray->insertObject(pHandler, u);
}

void CCTouchDispatcher::addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority)
{    
    CCTouchHandler *pHandler = CCStandardTouchHandler::handlerWithDelegate(pDelegate, nPriority);
    if (! m_bLocked)//如果没有被锁定
    {
        forceAddHandler(pHandler, m_pStandardHandlers);//注册到标准触摸事件的容器中
    }
    else
    {
        /* If pHandler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and return.
         * Refer issue #752(cocos2d-x)
         */
        if (ccCArrayContainsValue(m_pHandlersToRemove, pDelegate))//如果是属于待移除的委托,从容器中删除掉,并返回
        {
            ccCArrayRemoveValue(m_pHandlersToRemove, pDelegate);
            return;
        }
        //增加到带分发的缓冲容器中
        m_pHandlersToAdd->addObject(pHandler);
        //用于通知系统已有触摸事件准备待分发
        m_bToAdd = true;
    }
}

void CCTouchDispatcher::addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches)
{    
    CCTouchHandler *pHandler = CCTargetedTouchHandler::handlerWithDelegate(pDelegate, nPriority, bSwallowsTouches);
    if (! m_bLocked)//如果没有被锁定
    {
        forceAddHandler(pHandler, m_pTargetedHandlers);//注册到目标触摸事件的容器中
    }
    else
    {
        /* If pHandler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and return.
         * Refer issue #752(cocos2d-x)
         */
        if (ccCArrayContainsValue(m_pHandlersToRemove, pDelegate))//如果是属于待移除的委托,从容器中删除掉,并返回
        {
            ccCArrayRemoveValue(m_pHandlersToRemove, pDelegate);
            return;
        }
        //增加到带分发的缓冲容器中
        m_pHandlersToAdd->addObject(pHandler);
        //用于通知系统已有触摸事件准备待分发
        m_bToAdd = true;
    }
}

void CCTouchDispatcher::forceRemoveDelegate(CCTouchDelegate *pDelegate)
{
    CCTouchHandler *pHandler;

    // XXX: remove it from both handlers ???
    
    // remove handler from m_pStandardHandlers
    //从标准触摸容器中移除
    CCObject* pObj = NULL;
    CCARRAY_FOREACH(m_pStandardHandlers, pObj)
    {
        pHandler = (CCTouchHandler*)pObj;
        if (pHandler && pHandler->getDelegate() == pDelegate)//找到对应的委托
        {
            m_pStandardHandlers->removeObject(pHandler);//删除委托
            break;
        }
    }

    // remove handler from m_pTargetedHandlers
    //从目标触摸容器中移除
    CCARRAY_FOREACH(m_pTargetedHandlers, pObj)
    {
        pHandler = (CCTouchHandler*)pObj;
        if (pHandler && pHandler->getDelegate() == pDelegate)//找到对应的委托
        {
            m_pTargetedHandlers->removeObject(pHandler);//删除委托
            break;
        }
    }
}

void CCTouchDispatcher::removeDelegate(CCTouchDelegate *pDelegate)
{
    if (pDelegate == NULL)//参数检查
    {
        return;
    }

    if (! m_bLocked)//如果没有被锁定
    {
        forceRemoveDelegate(pDelegate);
    }
    else
    {
        /* If pHandler is contained in m_pHandlersToAdd, if so remove it from m_pHandlersToAdd and return.
         * Refer issue #752(cocos2d-x)
         */
        CCTouchHandler *pHandler = findHandler(m_pHandlersToAdd, pDelegate);//如果是属于待分发的委托,从容器中删除掉,并返回
        if (pHandler)
        {
            m_pHandlersToAdd->removeObject(pHandler);
            return;
        }
        //增加到带移除的缓冲容器中
        ccCArrayAppendValue(m_pHandlersToRemove, pDelegate);
        //用于通知系统已有触摸事件准备待移除
        m_bToRemove = true;
    }
}

void CCTouchDispatcher::forceRemoveAllDelegates(void)
{
     m_pStandardHandlers->removeAllObjects();//删除所有的标准触摸事件委托
     m_pTargetedHandlers->removeAllObjects();//删除所有的目标触摸事件委托
}

void CCTouchDispatcher::removeAllDelegates(void)
{
    if (! m_bLocked)//如果没有被锁定
    {
        forceRemoveAllDelegates();//删除标准触摸事件委托和目标触摸事件委托
    }
    else
    {
        m_bToQuit = true;//通知要临时取消触摸分发,即要移除掉所有标准触摸事件委托和目标触摸事件委托
    }
}

CCTouchHandler* CCTouchDispatcher::findHandler(CCTouchDelegate *pDelegate)
{
    CCObject* pObj = NULL;
    CCARRAY_FOREACH(m_pTargetedHandlers, pObj)//遍历目标触摸事件容器
    {
        CCTouchHandler* pHandler = (CCTouchHandler*)pObj;
        if (pHandler->getDelegate() == pDelegate)//找到对应的委托,返回它
        {
            return pHandler;
        }
    }

    CCARRAY_FOREACH(m_pStandardHandlers, pObj)//遍历标准触摸事件容器
    {
        CCTouchHandler* pHandler = (CCTouchHandler*)pObj;
        if (pHandler->getDelegate() == pDelegate)//找到对应的委托,返回它
        {
            return pHandler;
        }
    } 

    return NULL;
}

CCTouchHandler* CCTouchDispatcher::findHandler(CCArray* pArray, CCTouchDelegate *pDelegate)
{
    CCAssert(pArray != NULL && pDelegate != NULL, "");

    CCObject* pObj = NULL;
    CCARRAY_FOREACH(pArray, pObj)//遍历指定的触摸事件容器
    {
        CCTouchHandler* pHandle = (CCTouchHandler*)pObj;
        if (pHandle->getDelegate() == pDelegate)//找到对应的委托,返回它
        {
            return pHandle;
        }
    }

    return NULL;
}

void CCTouchDispatcher::rearrangeHandlers(CCArray *pArray)
{
    std::sort(pArray->data->arr, pArray->data->arr + pArray->data->num, less);//排序优先级
}

void CCTouchDispatcher::setPriority(int nPriority, CCTouchDelegate *pDelegate)
{
    CCAssert(pDelegate != NULL, "");

    CCTouchHandler *handler = NULL;

    handler = this->findHandler(pDelegate);//找到对应的委托

    CCAssert(handler != NULL, "");
	
    if (handler->getPriority() != nPriority)//判断是否需要设置优先级
    {
        handler->setPriority(nPriority);//设置优先级
        this->rearrangeHandlers(m_pTargetedHandlers);//设置完优先级后重新排序数组中的优先级
        this->rearrangeHandlers(m_pStandardHandlers);//设置完优先级后重新排序数组中的优先级
    }
}

//
// dispatch events
//
void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex)
{
    CCAssert(uIndex >= 0 && uIndex < 4, "");//参数检查

    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);//如果既要处理目标触摸事件也要处理标准触摸事件,则为true

    pMutableTouches = (bNeedsMutableSet ? pTouches->mutableCopy() : pTouches);//如果bNeedsMutableSet,则将要处理的触摸点拷贝一份出来,否则则引用它

    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)//遍历触摸点
        {
            pTouch = (CCTouch *)(*setIter);

            CCTargetedTouchHandler *pHandler = NULL;
            CCObject* pObj = NULL;
            CCARRAY_FOREACH(m_pTargetedHandlers, pObj)//遍历已被注册到目标触摸事件的容器
            {
                pHandler = (CCTargetedTouchHandler *)(pObj);//获取目标触摸句柄

                if (! pHandler)//为空,跳出循环
                {
                   break;
                }

                bool bClaimed = false;//初始化是否开始触摸处理
                if (uIndex == CCTOUCHBEGAN)//触摸开始事件
                {
                    bClaimed = pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent);//处理完开始触摸事件后返回true,则继续处理其他事件,且如果设置吞噬的话,则吞噬优先级比它低的事件

                    if (bClaimed)//如果是声明处理完了触摸点
                    {
                        pHandler->getClaimedTouches()->addObject(pTouch);//将触摸点加入到声明触摸容器中
                    }
                } else
                if (pHandler->getClaimedTouches()->containsObject(pTouch))//如果该触摸点是被放到声明触摸容器中的,则继续处理其他事件
                {
                    // moved ended canceled
                    bClaimed = true;

                    switch (sHelper.m_type)
                    {
                    case CCTOUCHMOVED://触摸移动事件
                        pHandler->getDelegate()->ccTouchMoved(pTouch, pEvent);
                        break;
                    case CCTOUCHENDED://触摸结束事件
                        pHandler->getDelegate()->ccTouchEnded(pTouch, pEvent);
                        pHandler->getClaimedTouches()->removeObject(pTouch);
                        break;
                    case CCTOUCHCANCELLED://触摸取消事件
                        pHandler->getDelegate()->ccTouchCancelled(pTouch, pEvent);
                        pHandler->getClaimedTouches()->removeObject(pTouch);
                        break;
                    }
                }

                if (bClaimed && pHandler->isSwallowsTouches())//处理吞噬事件
                {
                    if (bNeedsMutableSet)//如果是既要处理目标触摸事件也要处理标准触摸事件
                    {
                        pMutableTouches->removeObject(pTouch);//移除触摸
                    }

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

    //
    // 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();//移除所有触摸事件委托
    }
}

void CCTouchDispatcher::touchesBegan(CCSet *touches, CCEvent *pEvent)
{
    if (m_bDispatchEvents)//如果是触摸分发事件
    {
        this->touches(touches, pEvent, CCTOUCHBEGAN);//触摸开始
    }
}

void CCTouchDispatcher::touchesMoved(CCSet *touches, CCEvent *pEvent)
{
    if (m_bDispatchEvents)//如果是触摸分发事件
    {
        this->touches(touches, pEvent, CCTOUCHMOVED);//触摸移动
    }
}

void CCTouchDispatcher::touchesEnded(CCSet *touches, CCEvent *pEvent)
{
    if (m_bDispatchEvents)//如果是触摸分发事件
    {
        this->touches(touches, pEvent, CCTOUCHENDED);//触摸结束
    }
}

void CCTouchDispatcher::touchesCancelled(CCSet *touches, CCEvent *pEvent)
{
    if (m_bDispatchEvents)//如果是触摸分发事件
    {
        this->touches(touches, pEvent, CCTOUCHCANCELLED);//触摸结束
    }
}


所以要实现cocos2d-x的触摸事件,只要做两件事就可以了,继承触摸委托类CCTouchDelegate,重写它相应的方法;注册触摸事件到相应的触摸容器中;注册完后容器中相应的句柄会代用委托中相应的方法;最后在退出时从触摸容器中移除掉。下一篇文章将用使用CCLayer和CCMenu来实现以上过程。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值