鍍金池/ 教程/ Java/ 游戲暫停和觸摸屏蔽
游戲暫停和觸摸屏蔽
游戲場(chǎng)景過(guò)渡
碰撞檢測(cè)
跨平臺(tái)移植和廣告植入
批次渲染
觸摸事件和優(yōu)先級(jí)
背景音樂(lè)和音效
別急,先處理好CCScene和CCLayer的關(guān)系
自定義敵機(jī)精靈
UFO層特殊道具
主角的登場(chǎng)和幀動(dòng)畫(huà)
引擎坐標(biāo)系,錨點(diǎn)和背景滾動(dòng)
分?jǐn)?shù)的本地存儲(chǔ)
子彈層的處理
搞個(gè)飛機(jī)來(lái)玩玩

游戲暫停和觸摸屏蔽

一個(gè)游戲打到一半尿點(diǎn)咋整?難道要憋著。。。這不科學(xué)??!

好吧,把暫停游戲和恢復(fù)游戲的功能加進(jìn)去吧,否則也太對(duì)不起觀眾了!

1.暫停功能的加入

再給游戲加個(gè)層叫ControlLayer,這個(gè)層包含了2個(gè)元素,暫停功能和分?jǐn)?shù)顯示功能。分?jǐn)?shù)顯示和本地存儲(chǔ)在后面介紹。

我們先看看暫停功能是怎么加入的。

    //加入暫停按鈕
    bool ControlLayer::init()
    {
        bool bRet=false;
        do
        {
            CC_BREAK_IF(!CCLayer::init());

            CCSize winSize=CCDirector::sharedDirector()->getWinSize();

            //加入PauseMenu
            CCSprite* normalPause=CCSprite::create(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_pause_nor.png"));
            CCSprite* pressedPause=CCSprite::create(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_pause_pressed.png"));
            pPauseItem=CCMenuItemImage::create();//創(chuàng)建CCMenuItem
            pPauseItem->initWithNormalSprite(normalPause,pressedPause,NULL,this,menu_selector(ControlLayer::menuPauseCallback));//載入雙態(tài)圖和回調(diào)函數(shù)
            pPauseItem->setPosition(ccp(normalPause->getContentSize().width/2+10,winSize.height-normalPause->getContentSize().height/2-10));
            CCMenu *menuPause=CCMenu::create(pPauseItem,NULL);//創(chuàng)建CCMenu,可以這么理解CCMenuItem是CCMenu的孩子
            menuPause->setPosition(CCPointZero);
            this->addChild(menuPause,101);

            bRet=true;
        } while (0);

        return bRet;
    }
    //暫停按鍵的回調(diào)函數(shù)
    void ControlLayer::menuPauseCallback(CCObject* pSender)
    {
        if(!CCDirector::sharedDirector()->isPaused())//如果游戲處于正常狀態(tài)
        {
            //更改為恢復(fù)按鈕的雙態(tài)
            pPauseItem->setNormalSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_resume_nor.png"));
            pPauseItem->setSelectedSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_resume_pressed.png"));
            CCDirector::sharedDirector()->pause();//暫停游戲,這是導(dǎo)演控制的
        }
        else//否則
        {
            //更改為暫停按鈕的雙態(tài)
            pPauseItem->setNormalSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_pause_nor.png"));
            pPauseItem->setSelectedSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_pause_pressed.png"));
            CCDirector::sharedDirector()->resume();//開(kāi)麥拉!
        }
    }

這里沒(méi)有使用CCMenuItemToggle的原因是它沒(méi)辦法實(shí)現(xiàn)一個(gè)圖案的兩個(gè)狀態(tài)(normal和pressed),所以這里我手動(dòng)進(jìn)行替換。

2.游戲暫停狀態(tài)下的觸摸問(wèn)題

如果就這么完了,那也弱爆了。。。游戲的調(diào)試過(guò)程中發(fā)現(xiàn)了這么一個(gè)問(wèn)題,當(dāng)游戲暫停的時(shí)候,主角飛機(jī)仍然可以跟隨觸摸移動(dòng),這個(gè)bug就坑爹了,你可以在快掛掉的時(shí)候按下pause,把飛機(jī)挪到安全的位置,然后再按下resume,死不了了。。。

原來(lái)cocos2d-x在暫停CCScene之后觸摸仍然是有效的,所以我們需要在暫停之后屏蔽觸摸。

這個(gè)的解決方案主要是兩種:

(1)使用CCLayer的setTouchEnabled方法,但是這樣可能會(huì)引起程序的崩潰,因?yàn)橄到y(tǒng)在派發(fā)觸摸事件時(shí)發(fā)現(xiàn)響應(yīng)列表為空,會(huì)觸發(fā)一個(gè)斷言。

(2)寫(xiě)一個(gè)NoTouchLayer,在這個(gè)層里響應(yīng)觸摸并吞噬觸摸操作,使比它游戲級(jí)低的無(wú)法接收到觸摸分發(fā)。但是優(yōu)先級(jí)又不能高于CCMenu,也就是-128,不然恢復(fù)按鈕也會(huì)被屏蔽,導(dǎo)致游戲無(wú)法恢復(fù),除非是同一優(yōu)先級(jí)。使用方法就是addChild和removeChild。關(guān)于觸摸事件和優(yōu)先級(jí),請(qǐng)移步:,再次強(qiáng)調(diào),觸摸優(yōu)先級(jí)和addChild的Z軸順序無(wú)關(guān)。

    //NoTouchLayer.h
    class NoTouchLayer :
        public CCLayer
    {
    public:
        virtual bool init();

        // implement the "static node()" method manually
        LAYER_CREATE_FUNC(NoTouchLayer);

        virtual void registerWithTouchDispatcher();

        virtual bool ccTouchBegan (cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
        virtual void ccTouchMoved (cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
        virtual void ccTouchEnded (cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
    };

    //NoTouchLayer.cpp
    bool NoTouchLayer::init(){
        if (!CCLayer::init() )
        {
            return false;
        }
        setTouchEnabled(true);//設(shè)置觸摸有效
        return true;
    }

    void NoTouchLayer::registerWithTouchDispatcher()
    {
        CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -127 , true);//優(yōu)先級(jí)低于-128(CCMenu),同時(shí)高于其他層(0),true表示吞噬觸摸
        CCLayer::registerWithTouchDispatcher();
    }

    bool NoTouchLayer::ccTouchBegan (CCTouch *pTouch, CCEvent *pEvent)
    {
        return true;//返回true接收觸摸
    }

    void NoTouchLayer::ccTouchMoved (CCTouch *pTouch, CCEvent *pEvent)
    {
    }

    void NoTouchLayer::ccTouchEnded (CCTouch *pTouch, CCEvent *pEvent)
    {
    }

3.第三種暫停屏蔽觸摸的方法

因?yàn)橛螒蛑挥兄鹘强梢员挥|摸移動(dòng),所以只在PlaneLayer中的MoveTo函數(shù)里,做如下判斷:

    if(isAlive && !CCDirector::sharedDirector()->isPaused())

這樣就夠了。如果游戲暫停就不讓飛機(jī)移動(dòng)。好像也沒(méi)有什么問(wèn)題。

效果圖(暫停狀態(tài))

http://wiki.jikexueyuan.com/project/cocos2d-x-getting-real/images/11.1.jpeg" alt="" />