cocos2d-x触摸分发器道理

    添加时间:2013-7-1 点击量:


    为了实现触摸事务,CCLayer已经封装好了简单的接口(持续了CCTouchDelegate类)来实现触摸事务的响应。


     


    起首,触摸事务有两种:标准触摸和目标触摸。那么我们先看看如何开启这两种触摸。


    1.标准触摸


    在层初始化时调用setTouchEnable(true)办法即可实现标准触摸,实现处理惩罚事务回调函数,处理惩罚触摸事务即可。



     // optional
    
    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)


     


    第一个参数存放的是触摸点凑集,第二个参数为cocos2d-iphone遗留下的,在cocos2d-x中没有意义。那么在这4个触摸事务回调函数中参加事务处理惩罚代码即可。例:



    void TouchLayer::ccTouchesMoved(CCSet pTouches, CCEvent pEvent)
    
    {
    if(pTouches->count() == 1
    {
    CCTouch
    touch = dynamic_cast<CCTouch>(pTouches->anyObject());
    //因为在不合平台下触摸点的坐标系与OpenGL浮现区域的参数可能不尽雷同,所以触摸点的地位凡是与体系相干,须做如下处理惩罚即可获取触摸点在游戏中的地位了
    oint position
    = touch->locationInView();//获取游戏画面中的点地位
    position
    = CCDirector::sharedDirector()->convertToGL(position);//把屏幕左边转换为游戏坐标
    //此处处理惩罚触摸事务

    }
    else
    {
    //若是不止一个触摸点,则在此处处理惩罚多点触摸事务

    }
    }



    那么来看看setTouchEnable做了什么事,才让触摸回调函数被调用的呢



    void CCLayer::setTouchEnabled(bool enabled)
    
    {
    if (m_bTouchEnabled != enabled)
    {
    m_bTouchEnabled
    = enabled;
    if (m_bRunning)
    {
    if (enabled)
    {
    this->registerWithTouchDispatcher();
    }
    else
    {
    CCDirector::sharedDirector()
    ->getTouchDispatcher()->removeDelegate(this);
    }
    }
    }
    }


    再进入registerWithTouchDispatcher办法中看到调用了pDispatcher->addStandardDelegate(this, 0)办法,也就是将该对象注册为标准。


    对于标准,只要事务分发器接管到用户的触摸事务,就会分发给所有的订阅者;还有当体系存在多个触摸点时,所有的触摸点都邑传递给回调函数,然后很多景象下每个触摸点之间是自力的,屏幕上是否存在其他触摸点我们并不关怀。



    2.我们在来看看目标:


    要为该层应用目标,起首调用CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 0, true)开启目标(第二个参数为优先级,第三个参数为是否吞噬触摸)。然后重载事务回调函数:



        //重视返回类型,函数名,参数有什么不合
    
    virtual bool ccTouchBegan(CCTouch pTouch, CCEvent pEvent)
    // optional
    virtual void ccTouchMoved(CCTouch pTouch, CCEvent pEvent)
    virtual void ccTouchEnded(CCTouch pTouch, CCEvent pEvent)
    virtual void ccTouchCancelled(CCTouch pTouch, CCEvent pEvent)


    第一个参数为CCTouch,已不再是凑集,而是一个触摸点。ccTouchBegan办法返回的是一个布尔值,注解声明是否要捕获传入的这个触摸点,返回true默示要捕获,那么在后面Moved和Ended中处理惩罚触摸事务即可。若是注册的时辰选择了要吞噬触摸,触摸事务不会再分发下去,则优先级低的对象无法接管到触摸。



    那么实现一个对象的触摸就分为如下几步了:


    1)此对象持续CCStandardTouchDelegate / CCTargetedTouchDelegate接口


    2)应用addStandardDelegate / addTargetedDelegate办法把本身注册给触摸时候分发器CCTouchDispatcher 


    3)重载事务处理惩罚回调函数。(重视目标触摸开端时候Began中必须针对须要接管的事务返回true)


    4)当不再须要接管触摸事务时,应用removeDelegate办法来刊出触摸事务的接管。



    3. 触摸分发器道理


     来看看CCDispatcher的首要成员



        //注册标准触摸事务
    
    void addStandardDelegate(CCTouchDelegate pDelegate, int nPriority);
    //注册目标触摸事务
    void addTargetedDelegate(CCTouchDelegate pDelegate, int nPriority, bool bSwallowsTouches);
    //刊出触摸派发
    void removeDelegate(CCTouchDelegate pDelegate);
    void removeAllDelegates(void);
    //从头设定指定对象的事务优先级
    void setPriority(int nPriority, CCTouchDelegate pDelegate);

    //分发事务
    void touches(CCSet pTouches, CCEvent pEvent, unsigned int uIndex);

    protected:
    CCArray
    m_pTargetedHandlers; //记录注册了带目标的触摸事务对象
    CCArray m_pStandardHandlers; //记录注册了标准触摸事务的对象



    当触摸分发器从体系接管到触摸事务后,还须要一一分发给触摸处理惩罚对象,此中事务分发的相干代码首要集中在touches办法中。



    // dispatch events
    
    void CCTouchDispatcher::touches(CCSet pTouches, CCEvent pEvent, unsigned int uIndex)
    {
    //。。。。。。。。。
    // 1。处理惩罚带目标的触摸事务
    if (uTargetedHandlersCount > 0
    {
    CCTouch
    pTouch;
    CCSetIterator setIter;
    //1.1 遍历每一个从体系接管到的触摸事务
    for (setIter = pTouches->begin(); setIter != pTouches->end(); ++setIter)
    {
    pTouch
    = (CCTouch )(setIter);
    CCTargetedTouchHandler
    pHandler = NULL;
    CCObject
    pObj = NULL;
    //1.2 遍历每一个已注册目标触摸事务的对象,分发事务
    CCARRAY_FOREACH(m_pTargetedHandlers, pObj)
    {
    pHandler
    = (CCTargetedTouchHandler )(pObj);
    if (! pHandler)
    break;
    bool bClaimed = false;
    //起首处理惩罚触摸开端时候
    if (uIndex == CCTOUCHBEGAN)
    {
    bClaimed
    = pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent);
    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;
    }
    }
    }
    }

    // 2. 处理惩罚标准触摸事务
    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;
    }
    }
    }

    //。。。。。。
    //删除 标识表记标帜为吞噬的触摸事务

    }


    在触摸凑集中的每一个触摸点,遵守优先级询问每一个注册到分发器的对象。


    拥有最低优先级(正无穷)的目标的优先级 要比 拥有高优先级(负无穷)的标准的优先级 高。


    对于目标,只有在开端事务中返回true,后续事务(移动、停止、作废)才会持续分发给目标对象。


    若是设置了吞噬,被捕获到的点会被吞噬掉,被吞噬的点将立即移除触摸凑集,不在分发给后续目标。



    值得重视的是:接管触摸的对象并不必然正显示在屏幕上。触摸分发器和引擎中的画图是彼此对的,所以在不须要的时辰及时从触摸分发器中移除触摸。




    所有随风而逝的都属于昨天的,所有历经风雨留下来的才是面向未来的。—— 玛格丽特·米切尔 《飘》
    分享到: