首先是層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!