cocos2d-x中層和菜單的觸摸控制

首先是層CCLayer,其實CCLayer已經繼承了觸摸委託類了

class CC_DLL CCLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate


這樣一來只要重寫它的方法便可處理相應的觸摸操作:

class CC_DLL CCLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate
{
public:
    ...
    
    // default implements are used to call script callback if exist
    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);

    // default implements are used to call script callback if exist
    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);
    
    virtual void registerWithTouchDispatcher(void);//註冊觸摸監聽
    
   
    virtual bool isTouchEnabled();//是否開啓觸摸
    virtual void setTouchEnabled(bool value);//設置該層是否允許觸摸
    
    virtual void setTouchMode(ccTouchesMode mode);//設置觸摸模式
    virtual int getTouchMode();//獲取觸摸模式
    
    /** priority of the touch events. Default is 0 */
    virtual void setTouchPriority(int priority)//設置觸摸優先級
    virtual int getTouchPriority();//獲取觸摸優先級

    ...
protected:   
    bool m_bTouchEnabled;//記錄是否允許觸摸
    ...
    
private:
    ...
    
    int m_nTouchPriority;//記錄觸摸優先級
    ccTouchesMode m_eTouchMode;//記錄觸摸模式
    
    ...
};
其實要開啓該層的觸摸只要調用setTouchEnabled方法即可,因爲裏面已經幫我們實現了註冊觸摸事件到分發器中。

void CCLayer::setTouchEnabled(bool enabled)
{
    if (m_bTouchEnabled != enabled)//判斷是否需要執行下面操作
    {
        m_bTouchEnabled = enabled;//更新是否允許觸摸
        if (m_bRunning)//如果是正在運行的層
        {
            if (enabled)//如果是開啓
            {
                this->registerWithTouchDispatcher();//註冊觸摸事件到分發器
            }
            else
            {
                // have problems?
                CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);//從分發器中移除,關閉觸摸
            }
        }
    }
}
void CCLayer::registerWithTouchDispatcher()
{
    CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher();

    // Using LuaBindings
    if (m_pScriptTouchHandlerEntry)//腳本相關
    {
	    if (m_pScriptTouchHandlerEntry->isMultiTouches())
	    {
	       pDispatcher->addStandardDelegate(this, 0);
	       LUALOG("[LUA] Add multi-touches event handler: %d", m_pScriptTouchHandlerEntry->getHandler());
	    }
	    else
	    {
	       pDispatcher->addTargetedDelegate(this,
						m_pScriptTouchHandlerEntry->getPriority(),
						m_pScriptTouchHandlerEntry->getSwallowsTouches());
	       LUALOG("[LUA] Add touch event handler: %d", m_pScriptTouchHandlerEntry->getHandler());
	    }
    }
    else
    {
        if( m_eTouchMode == kCCTouchesAllAtOnce ) {//判斷是否是標準觸摸
            pDispatcher->addStandardDelegate(this, 0);//註冊到標準觸摸分發器中
        } else {
            pDispatcher->addTargetedDelegate(this, m_nTouchPriority, true);//註冊到目標觸摸分發器中,默認優先級m_nTouchPriority爲0
        }
    }
}
默認情況下層開啓的是標準觸摸,如果要改成目標觸摸,設置該層的觸摸模式即可,即調用setTouchMode方法。

當然當層被移除時要從分發器中移除觸摸事件,如果有開啓觸摸的話:

void CCLayer::onExit()
{
    CCDirector* pDirector = CCDirector::sharedDirector();
    if( m_bTouchEnabled )//如果開啓了觸摸
    {
        pDirector->getTouchDispatcher()->removeDelegate(this);//移除觸摸
        // [lua]:don't unregister script touch handler, or the handler will be destroyed
        // unregisterScriptTouchHandler();
    }

    // remove this layer from the delegates who concern Accelerometer Sensor
    if (m_bAccelerometerEnabled)
    {
        pDirector->getAccelerometer()->setDelegate(NULL);
    }

    // remove this layer from the delegates who concern the keypad msg
    if (m_bKeypadEnabled)
    {
        pDirector->getKeypadDispatcher()->removeDelegate(this);
    }

    CCNode::onExit();
}


其次是菜單的觸摸操作。菜單是繼承自於CCLayerRGBA,而CCLayerRGBA又繼承自與CCLayer,所有菜單同樣是繼承了觸摸委託類。

class CC_DLL CCMenu : public CCLayerRGBA
class CC_DLL CCLayerRGBA : public CCLayer, public CCRGBAProtocol

默認情況下,菜單的觸摸優先級非常高,是-128,被聲明在一個枚舉中

enum {
    //* priority used by the menu for the event handler
    kCCMenuHandlerPriority = -128,//菜單默認的觸摸優先級
};

菜單的觸摸實現幾乎跟層的一樣,只不過菜單默認是開啓觸摸的,而層是沒有開啓,需要手動開啓,並也已經重寫觸摸的4個操作方法

    virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
    virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);
    virtual void ccTouchCancelled(CCTouch *touch, CCEvent* event);
    virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
這樣一來開發者就無需去處理這些觸摸方法,所以在初始化菜單就已經幫我們開啓了觸摸,設置爲目標觸摸和並帶有吞噬。
bool CCMenu::init()
{
    return initWithArray(NULL);
}

bool CCMenu::initWithArray(CCArray* pArrayOfItems)
{
    if (CCLayer::init())
    {
        setTouchPriority(kCCMenuHandlerPriority);//設置菜單的觸摸優先級(kCCMenuHandlerPriority = -128)
        setTouchMode(kCCTouchesOneByOne);//設置菜單的觸摸模式爲目標觸摸,並帶有吞噬
        setTouchEnabled(true);//開啓觸摸

        m_bEnabled = true;//記錄已開啓觸摸
        ...
        
        return true;
    }
    return false;
}
同樣,在移除菜單也要把觸摸事件從分發器中移除:

void CCMenu::onExit()
{
    if (m_eState == kCCMenuStateTrackingTouch)
    {
        if (m_pSelectedItem)
        {
            m_pSelectedItem->unselected();
            m_pSelectedItem = NULL;
        }
        
        m_eState = kCCMenuStateWaiting;
    }

    CCLayer::onExit();//調用父類的onExit,它會幫菜單將觸摸事件從分發器中移除掉,取消掉觸摸監聽
}

所以只要理解了觸摸原理,如何處理這些觸摸事件簡直就是很easy!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章