cocos2dx基礎篇(7) 觸碰事件
cocos2dx遊戲引擎的重點是在於移動裝置的跨平臺開發,而移動裝置上的遊戲大部分都是通過螢幕觸碰來進行的。比如主選單的按鈕觸碰,打飛機中飛機的觸碰移動,都需要用到觸碰操作。想一想之前講的選單按鈕CCMenu,選單項的點選響應事件,其實就是觸碰。
cocos2dx引擎中實現觸碰的類CCTouchDelegate。而CCLayer類預設繼承了CCTouchDelegate介面,所以CCLayer的子類無須再重新使用這些介面,這樣就很方便地為我們提供了觸控操作相關的操作。
觸碰事件主要分為兩類:單點觸碰 和 多點觸碰。
【本節內容】
一、單點觸碰TargetedDelegate、以及引數CCTouch類。
二、多點觸碰StandardDelegate、以及引數CCSet類。
三、兩類觸碰的區別。
【單點觸碰】
單點觸碰TargetedDelegate,顧名思義,就是隻接受一個點的觸控響應事件。
在使用觸碰之前,必須要先註冊觸碰委託。單點觸碰的註冊委託函式為addTargetedDelegate。
1、開啟單點觸碰事件addTargetedDelegate
寫在onEnter()中。
// /** * 開啟單點觸碰TargetedDelegate * 註冊觸碰:addTargetedDelegate("觸碰事件委託的物件","優先順序","是否攔截觸屏事件"); * 優先順序的值越小,就越高越早被響應。 * 當第3個引數為true時,表示對本次觸屏事件進行攔截,也就是說當觸屏事件響應了本次觸屏委託後,將不會再繼續響應其他觸碰委託。 */ void HelloWorld::onEnter() { //註冊觸碰響應事件 CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,false); CCLayer::onEnter();//一定不要忘了呼叫父類的onEnter } //
2、關閉單點觸碰事件removeDelegate
寫在onExit()中。
// /** * 關閉單點觸碰TargetedDelegate * 登出觸碰:removeDelegate("登出觸碰事件委託的物件"); */ void HelloWorld::onExit() { //登出觸屏響應事件 CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this); CCLayer::onExit();//一定不要忘了呼叫父類的onExit } //
3、單點觸碰響應函式
ccTouchBegan、ccTouchMoved、ccTouchEnded、ccTouchCancelled。
其中ccTouchBegan的返回值為bool型別:
當返回true時 ,表示繼續響應ccTouchMoved、ccTouchEnded事件;
當返回false時,則不再繼續響應這兩個事件。
//
virtual bool ccTouchBegan(CCTouch* touch,CCEvent* event); //手指碰到螢幕時呼叫
virtual void ccTouchMoved(CCTouch* touch,CCEvent* event); //手指在螢幕上滑動時呼叫
virtual void ccTouchEnded(CCTouch* touch,CCEvent* event); //手指離開螢幕是呼叫
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent); //取消觸碰
//
4、關於CCTouch類
CCTouch類是用來儲存使用者觸控式螢幕幕的過程中,其觸控點的相關資訊。也就是儲存了觸碰的整個過程中,手指所在的位置座標。
需要在.h中新增引用名稱空間:using namespace cocos2d; 才可以使用。
常用操作如下:
//
class CCTouch : public CCObject
{
CCPoint getLocation(); //返回當前觸點的座標
CCPoint getPreviousLocation(); //返回前一個觸點的座標
CCPoint getStartLocation(); //返回開始觸碰時的座標
CCPoint getDelta(); //返回最近兩個觸點的偏移量座標
};
//
5、程式碼實戰
接下來將舉個例子:使用單點觸碰實現精靈的移動。
5.1、宣告單點觸碰響應函式
先在HelloWorld.h中,宣告觸碰響應函式,以及類的生命週期。
//
//觸屏事件
virtual bool ccTouchBegan(CCTouch* touch,CCEvent* event);
virtual void ccTouchMoved(CCTouch* touch,CCEvent* event);
virtual void ccTouchEnded(CCTouch* touch,CCEvent* event);
//生命週期
virtual void onEnter();
virtual void onExit();
//
5.2、開啟、關閉單點觸碰事件
在HelloWorld.cpp中編寫開啟和關閉觸碰事件。
//
//開啟觸屏監聽
void HelloWorld::onEnter()
{
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,false);
CCLayer::onEnter(); //一定不要忘了
}
//關閉觸屏監聽
void HelloWorld::onExit()
{
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
CCLayer::onExit(); //一定不要忘了
}
//
5.3、建立測試精靈
在HelloWorld::init()中建立一個CCSprite精靈,用於測試觸碰。
//
//新增一個CCSprite精靈
CCSprite* sp = CCSprite::create("Icon.png");
sp->setPosition( midPos );
this->addChild(sp, 0, 1); //tag標記為1
//
5.4、實現觸碰響應函式
ccTouchBegan:將精靈的位置設定到觸碰開始的位置。關鍵函式:touch->getLocation()
ccTouchMoved:對精靈的位置進行移動。 關鍵函式:touch->getDelta()
ccTouchEnded:將精靈的位置還原到觸碰開始的位置。關鍵函式:touch->getStartLocation()
//
//觸屏開始ccTouchBegan
bool HelloWorld::ccTouchBegan(CCTouch* touch,CCEvent * event)
{
CCLOG("ccTouchBegan");
//獲取CCSprite精靈
CCSprite* sp = (CCSprite*)this->getChildByTag(1);
//設定精靈的座標為: 當前觸點位置
CCPoint pTouch = touch->getLocation();
sp->setPosition( pTouch );
return true;
}
//觸屏移動ccTouchMoved
void HelloWorld::ccTouchMoved(CCTouch* touch,CCEvent* event)
{
CCLOG("ccTouchMoved");
//獲取可視區域尺寸大小
CCSize mysize = CCDirector::sharedDirector()->getVisibleSize();
//獲取CCSprite精靈
CCSprite* sp = (CCSprite*)this->getChildByTag(1);
//實現精靈的觸屏移動
CCPoint pos = touch->getDelta(); //獲得觸屏滑動的偏移量
CCPoint currentPos = sp->getPosition(); //獲得精靈的當前座標
currentPos = ccpAdd(currentPos, pos); //精靈+偏移量 後的座標
sp->setPosition(currentPos); //設定觸屏移動後的座標
}
//觸屏結束ccTouchEnded
void HelloWorld::ccTouchEnded(CCTouch* touch,CCEvent* event)
{
CCLOG("ccTouchEnded");
//獲取CCSprite精靈
CCSprite* sp = (CCSprite*)this->getChildByTag(1);
//設定精靈的座標為: 觸屏開始時的觸點位置
CCPoint touchStartPos = touch->getStartLocation();
sp->setPosition( touchStartPos );
}
//
6、執行結果
【多點觸碰】
多點觸碰StandardDelegate,可以支援多個點的同時觸控響應事件。
1、開啟多點觸碰
多點觸碰的委託註冊放在onEnter的生命函式中會造成程式異常退出。
所以註冊多點觸碰都需要重寫如下函式:registerWithTouchDispatcher。
開啟多點觸碰,除了註冊觸碰委託外,還需要呼叫setTouchEnabled(true)來啟用觸碰。
//
/**
* 註冊多點觸碰,重寫registerWithTouchDispatcher。
* addStandardDelegate("觸碰事件委託的物件","優先順序")
*/
void HelloWorld::registerWithTouchDispatcher()
{
CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this,0);
}
//在HelloWorld::init()中啟用多點觸碰
this->setTouchEnabled(true);
//
2、關閉多點觸碰
與單點觸碰的關閉類似,寫在onExit()。
//
void HelloWorld::onExit()
{
//關閉觸碰
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
CCLayer::onExit(); //一定不要忘了
}
//
3、多點觸碰響應函式
ccTouchesBegan、ccTouchesMoved、ccTouchesEnded、ccTouchesCancelled。
其中ccTouchesBegan和單點觸碰不同,返回值為void。
//
virtual void ccTouchesBegan(CCSet* touches, CCEvent* event); //觸碰開始
virtual void ccTouchesMoved(CCSet* touches, CCEvent* event); //觸碰移動
virtual void ccTouchesEnded(CCSet* touches, CCEvent* event); //觸碰結束
virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent); //取消多點觸屏
//
4、關於CCSet類
CCSet類是一個集合類,和C++中的Set是類似的。
在這裡CCSet的資料元素型別為CCTouch,其主要儲存的是多點觸碰的觸控點CCTouch集合。
使用迭代器CCSetIterator進行CCSet集合中多個觸點CCTouch的遍歷。
//
for (CCSetIterator iter = touches->begin() ;iter != touches->end(); iter++)
{
//獲取觸點後,就和單點一樣的處理了
CCTouch* touch = (CCTouch*)(*iter);
//......
}
//
5、程式碼實戰
在電腦中無法看到多點觸碰的效果,因為……電腦操作只有一個滑鼠。
下面就講解一個多點觸碰的例子吧,至於效果,自己將程式碼移植到手機上看吧。。。
5.1、宣告多點觸碰響應函式
先在HelloWorld.h中,宣告多點觸碰響應函式,以及類的生命週期。
//
//觸屏事件
virtual void registerWithTouchDispatcher(void);
virtual void ccTouchesBegan(CCSet* touches,CCEvent* event);
virtual void ccTouchesMoved(CCSet* touches,CCEvent* event);
virtual void ccTouchesEnded(CCSet* touches,CCEvent* event);
//生命週期
virtual void onExit();
//
5.2、開啟、關閉多點觸碰事件
在HelloWorld.cpp中編寫開啟和關閉多點觸碰事件。
//
//在init中開啟多點觸碰
bool HelloWorld::init()
{
//.....
//開啟多點觸屏。注意這句話必須要寫,否則無法多點觸屏
this->setTouchEnabled(true);
//.....
}
//註冊多點觸屏
void HelloWorld::registerWithTouchDispatcher()
{
CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this,0);
}
//登出多點觸屏
void HelloWorld::onExit()
{
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
CCLayer::onExit(); //不要忘了寫!
}
//
5.3、建立測試精靈
在HelloWorld::init()中建立兩個CCSprite精靈,用於測試觸碰。
//
//新增兩個CCSprite精靈,用於多點觸屏
CCSprite* sp1 = CCSprite::create("Icon.png");
sp1->setPosition( ccp( 100, 160 ) );
this->addChild(sp1, 0, 1);
CCSprite* sp2 = CCSprite::create("Icon_gray.png");
sp2->setPosition( ccp( 200, 160) );
this->addChild(sp2, 0, 2);
//
5.4、實現多點觸碰響應函式
ccTouchesMoved中:將精靈的位置設定到觸點位置,sp1精靈設定到第0個觸點位置;sp2精靈設定到第1個觸點位置。
關鍵函式:
(1)CCTouch* touch = (CCTouch*)(*iter)
(2)touch->getID()
//
//觸屏開始,返回值是void
void HelloWorld::ccTouchesBegan(CCSet* touches,CCEvent* event)
{
CCLOG("ccTouchesBegan");
}
//觸屏移動
void HelloWorld::ccTouchesMoved(CCSet* touches,CCEvent* event)
{
CCLOG("ccTouchesMoved");
//建立CCSet的迭代器CCSetIterator
CCSetIterator iter = touches->begin();
//遍歷多點觸點集合touches
for( ;iter != touches->end(); iter++)
{
//獲取觸點後,就和單點一樣的處理了
CCTouch* touch = (CCTouch*)(*iter);
if( touch->getID() == 0) //控制精靈sp1
{
CCSprite* sp1 = (CCSprite*)this->getChildByTag(1);
sp1->setPosition( touch->getLocation() );
}
else if( touch->getID() == 1) //控制精靈sp2
{
CCSprite* sp2 = (CCSprite*)this->getChildByTag(2);
sp2->setPosition( touch->getLocation() );
}
}
}
//觸屏結束
void HelloWorld::ccTouchesEnded(CCSet* touches,CCEvent* event)
{
CCLOG("ccTouchesEnded");
}
//
6、執行結果
想要看到多點觸碰的效果,就把程式移植到手機上吧。
【兩類觸碰的區別】
(1)單點使用的監聽類是CCtargetedTouchDelegate,而多點使用CCtangardTouchDelegate。
(2)多點觸控還需要多一個步驟,就是單獨寫個函式來註冊多點觸控:registerWithTouchDispatcher。
(3)多點觸控要有開啟才能用。 this->setTouchEnabled(true)。
(4)多點觸控中的ccTouchesBegan不是布林型。