cocos2d-x触摸流程解析

           用cocos2d-x有一段时间了,对其中的触摸机制一直都是依葫芦画瓢来使用没有深入的了解过,今天闲来无事,具体分析下它的触摸机制。

1.最基本的触摸委托类CCTouchDelegate。

该类封装了一些基本的触摸操作如下:

         virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
         virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
         virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
         virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent)

         virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) 
         virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) 
         virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
         virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent)

具体作用大家看函数名就能明白。从CCTouchDelegate又派生了两个类CCTargetedTouchDelegate和CCStandardTouchDelegate。

CCTargetedTouchDelegate的方法如下:

        virtual void ccTouchBegan(CCSet *pTouches, CCEvent *pEvent)
        virtual void ccTouchMoved(CCSet *pTouches, CCEvent *pEvent)
        virtual void ccTouchEnded(CCSet *pTouches, CCEvent *pEvent)
        virtual void ccTouchCancelled(CCSet *pTouches, CCEvent *pEvent) 

CCStandardTouchDelegate的方法如下:

        virtual bool ccTouchesBegan(CCTouch *pTouch, CCEvent *pEvent) 
        virtual void ccTouchesMoved(CCTouch *pTouch, CCEvent *pEvent) 
        virtual void ccTouchesEnded(CCTouch *pTouch, CCEvent *pEvent)
        virtual void ccTouchesCancelled(CCTouch *pTouch, CCEvent *pEvent) 

可见CCTargetedTouchDelegate覆盖了CCTouchDelegate中ccTouches.....系列方法,CCStandardTouchDelegate覆盖了CCTouchDelegate中ccTouch系列方法。因此CCTargetedTouchDelegate是用来响应单点触摸,而CCStandardTouchDelegate是用来响应多点触摸事件。

2.所有需要响应触摸的类都需要继承CCTouchDelegate或其派生类,覆盖相应的ccTouch....或者ccTouches....系列函数。如引擎中的CCLayer就会继承CCTouchDelegate类并覆盖响应的触摸操作函数。

3.触摸事件的注册

CCTouchDispatcher类闪亮登场。该类有两个重要成员如下:

CCArray* m_pTargetedHandlers;
CCArray* m_pStandardHandlers;

分别保存了CCTargetedTouchHandler和CCStandardTouchHandler类型的数组。这两个类其实就是封了CCTargetedTouchDelegate和CCStandardTouchDelegate。现在来看具体的事件注册过程,CCNode有registerWithTouchDispatcher成员函数,当该Node被启用时在OnEnter函数中会被调用。具体实现如下:

void CCNode::registerWithTouchDispatcher()
{

    CCLOG("CCNODE: REGISTER WITH TOUCH DISPATHCER <%p>", this);
    CCScene *scene = getScene();
    if (scene)
    {
        scene->addTouchableNode(this);
    }
}

其实就是调用了CCScene的addTouchableNode函数,实现如下:

void CCScene::addTouchableNode(CCNode *node)
{
    if (!m_touchableNodes->containsObject(node))
    {
        m_touchableNodes->addObject(node);
//        CCLOG("ADD TOUCHABLE NODE <%p>", node);
        if (!m_touchDispatchingEnabled)
        {
            enableTouchDispatching();
        }
    }
}

该函数做了两件事情,1.将该要响应触摸事件的node添加到CCScene的m_touchableNodes中。2.调用了enableTouchDispatching函数,该函数实现如下:

void CCScene::enableTouchDispatching()
{
    if (!m_touchRegistered)
    {
        CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this, 0);
        m_touchRegistered = true;
    }
    m_touchDispatchingEnabled = true;
}

CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this, 0)这段代码会将CCScene保存到CCTouchDispatcher的m_pStandardHandlers成员中方便以后触发。

可见给某个CCNode注册触摸事件时会先给CCNode所属的CCScene注册触摸事件然后将该CCNode保存到CCScene的m_touchableNodes成员变量中。

4.触摸事件的分发

CCTouchDispatcher的touchesBegan被调用,该函数接收底层(windows,ios,android各不相同)传过来的点的坐标类型等参数。该函数内部调用CCTouchDispatcher的touches函数。该函数最核心部分如下:

CCARRAY_FOREACH(m_pStandardHandlers, pObj)

///此处省略非重要代码

pHandler = (CCStandardTouchHandler*)(pObj);

///此处省略非重要代码

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

就是遍历CCStandardTouchHandler然后调用成员的ccTouchesBegan等操作函数(对CCTargetedTouchHandler的操作和这类似)。之前注册CCNode触摸事件时会把该CCNode所属的CCScene放到CCStandardTouchHandler中,所以此时会调用CCScene的ccTouchesBegan函数如下:

void CCScene::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)

{

       ///此处省略非重要代码

       CCARRAY_FOREACH(m_touchableNodes, obj)

       ///此处省略非重要代码

       if (touchMode == kCCTouchesAllAtOnce)
       {
            node->ccTouchesBegan(pTouches, pEvent);
       }
       else
       {
             ret = node->ccTouchBegan(touchTarget->findTouch(pTouches), pEvent);
       }

        ///此处省略非重要代码

}

会遍历m_touchableNodes调用所有成员的ccTouchesBegan函数,从而将触摸事件分发到每一个注册过的CCNode中。

5.关于所有继承于Widget类的控件的触摸机制。

几个重要的成员函数如下:

void addTouchEventListener(CCObject* target,SEL_TouchEvent selector);

virtual bool onTouchBegan(CCTouch *touch, CCEvent *unused_event);
virtual void onTouchMoved(CCTouch *touch, CCEvent *unused_event);
virtual void onTouchEnded(CCTouch *touch, CCEvent *unused_event);
virtual void onTouchCancelled(CCTouch *touch, CCEvent *unused_event);

addTouchEventListener实现如下:

void Widget::addTouchEventListener(CCObject *target, SEL_TouchEvent selector)
{
    _touchEventListener = target;
    _touchEventSelector = selector;
}

就是将触摸对象和回调保存到_touchEventListener 和_touchEventSelector 中。

bool Widget::onTouchBegan(CCTouch *touch, CCEvent *unused_event)

{

        ///此处省略非重要代码

        pushDownEvent();

         ///此处省略非重要代码

}

void Widget::pushDownEvent()
{
    if (_touchEventListener && _touchEventSelector)
    {
        (_touchEventListener->*_touchEventSelector)(this,TOUCH_EVENT_BEGAN);
    }
}

Widget的onTouchBegan在TouchGroup的checkTouchEvent中调用如下:

bool TouchGroup::checkTouchEvent(Widget *root, CCTouch* touch, CCEvent* pEvent)

{

    ccArray* arrayRootChildren = root->getChildren()->data;
    int length = arrayRootChildren->num;
    for (int i=length-1; i >= 0; i--)
    {
        Widget* widget = (Widget*)(arrayRootChildren->arr[i]);
        if (checkTouchEvent(widget, touch, pEvent))
        {
            return true;
        }
    }
    bool pass = root->onTouchBegan(touch, pEvent);//在此处调用
    if (root->_hitted)
    {
        m_pSelectedWidgets->addObject(root);
        return true;
    }
    return pass;

}

TouchGroup的checkTouchEvent其实是在TouchGroup的ccTouchBegan函数中被调用,其实就是走的CCTouchDispatcher分发的一套流程。

6.总结

    cocos2d-x的触摸机制基本就是以CCTouchDelegate委托类和CCTouchDispatcher分发注册类为核心各种派生辅助类来实现的。了解了其原理在实际使用时就会更加灵活,如实现控件的不规则响应区域等。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值