1. 程式人生 > >cocos2dx基礎篇(7) 觸碰事件

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、執行結果

wKioL1PzS6fQI6SVAAb7815Wxrw807.gif

【多點觸碰】

    多點觸碰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、執行結果

wKiom1PzWOfTmCYbAAusxeY8uuc353.gif

想要看到多點觸碰的效果,就把程式移植到手機上吧。

兩類觸碰的區別】

    (1)單點使用的監聽類是CCtargetedTouchDelegate,而多點使用CCtangardTouchDelegate。

    (2)多點觸控還需要多一個步驟,就是單獨寫個函式來註冊多點觸控:registerWithTouchDispatcher。

    (3)多點觸控要有開啟才能用。 this->setTouchEnabled(true)。

    (4)多點觸控中的ccTouchesBegan不是布林型。