Cocos2d-x 碰撞檢測(cè)

2018-10-02 09:51 更新

碰撞檢測(cè)

碰撞檢測(cè)是整個(gè)游戲的重頭戲,沒有它,子彈和敵機(jī)只能是路人。。。雖然很重要,但實(shí)現(xiàn)起來確是很簡單。

1.update函數(shù)

每個(gè)從CCObject繼承的類都包含了一個(gè)update函數(shù),它是一個(gè)內(nèi)聯(lián)虛函數(shù),執(zhí)行頻率為每幀調(diào)用一次。

原型:

    virtual CCObject::update(float dt);

開啟方式:

    this->scheduleUpdate();

關(guān)閉方式:

    this->unscheduleUpdate();

有了這個(gè)update函數(shù),我們就可以在GameLayer中對(duì)它進(jìn)行重載,把我們每幀內(nèi)要執(zhí)行的動(dòng)作放到update中,進(jìn)行調(diào)用就可以了。

2.碰撞檢測(cè)原理

那我們每幀內(nèi)要做什么事呢?

我們先看一下游戲是什么?動(dòng)畫?其實(shí)不過是一張張快速變換的圖片。比如我們?cè)O(shè)置60FPS,那么游戲就是一秒鐘閃過60張圖片,由于人眼的視覺殘留效應(yīng)導(dǎo)致看起來像是動(dòng)畫,因此游戲中的每一個(gè)動(dòng)作我們可以認(rèn)為是高速變化的靜態(tài)的圖片,而這個(gè)圖片是以幀為單位。

所以我們可以在每一幀內(nèi)進(jìn)行碰撞檢測(cè)。

原理:

主角飛機(jī)是一個(gè)精靈,也就是一張帶alpha通道的PNG圖,子彈也是,敵機(jī)同樣也是,它們都是一塊矩形區(qū)域,即便有的地方是透明的。所以碰撞檢測(cè)就是在每一幀內(nèi)判斷多個(gè)不同類型矩形區(qū)域是否有相交,有即碰撞。

3.碰撞檢測(cè)示例

這里以生命值最大的Enemy3來做示例。而敵機(jī)和主角的碰撞是一樣的道理。主角的爆炸效果也是采用幀動(dòng)畫,和敵機(jī)爆炸是一致的,但是要注意,主角飛機(jī)一旦爆炸,要記得StopShoot。

    CCArray* bulletsToDelete=CCArray::create();//創(chuàng)建一個(gè)CCArray,用以存放待刪除的子彈,也就是此幀中被檢測(cè)到碰撞的子彈
    bulletsToDelete->retain();//必須調(diào)用retain,CCArray內(nèi)部調(diào)用了autoRelease
    CCObject* bt,*et;

    //enemy3 & bullet CheckCollosion
    CCARRAY_FOREACH(this->bulletLayer->m_pAllBullet,bt)//遍歷所有子彈
    {
        CCSprite* bullet=(CCSprite*)bt;

        CCArray* enemy3sToDelete=CCArray::create();//創(chuàng)建一個(gè)CCArray,用以存放待刪除的敵機(jī),也就是此子彈擊中的敵機(jī)
        enemy3sToDelete->retain();//調(diào)用retain
        CCARRAY_FOREACH(this->enemyLayer->m_pAllEnemy3,et)//遍歷所有敵機(jī)
        {
            Enemy* enemy3=(Enemy*)et;
            if (CCRect::CCRectIntersectsRect(bullet->boundingBox(),enemy3->getBoundingBox()))//檢測(cè)碰撞,即矩形區(qū)域是否相交
            {
                //如果life>1,移除bullet
                if (enemy3->getLife()>1)//因?yàn)镋nemy3設(shè)置了生命值為5
                {
                    enemy3->loseLife();
                    bulletsToDelete->addObject(bullet);//把待刪除子彈放入CCArray
                }
                //如果life==1,移除enemy3
                else if(enemy3->getLife()==1)//只剩一條命的時(shí)候,再碰撞就掛掉了
                {
                    enemy3->loseLife();
                    bulletsToDelete->addObject(bullet);//把待刪除子彈放入CCArray
                    enemy3sToDelete->addObject(enemy3);//把待刪除敵機(jī)放入CCArray
                    score+=ENEMY3_SCORE;
                    this->controlLayer->updateScore(score);
                }
                //此時(shí)處在敵機(jī)爆炸動(dòng)畫階段,敵機(jī)未消失,子彈還有打到的機(jī)會(huì),所以不進(jìn)行檢測(cè)
                else ;
            }
        }
        CCARRAY_FOREACH(enemy3sToDelete,et)//遍歷所有此幀中碰撞死亡的敵機(jī),必須是死亡
        {
            Enemy* enemy3=(Enemy*)et;
            this->enemyLayer->enemy3Blowup(enemy3);//執(zhí)行爆炸
        }
        enemy3sToDelete->release();//release
    }
    CCARRAY_FOREACH(bulletsToDelete,bt)//遍歷所有此幀中碰撞的子彈
    {
        CCSprite* bullet=(CCSprite*)bt;
        this->bulletLayer->RemoveBullet(bullet);//執(zhí)行移除
    }
    bulletsToDelete->removeAllObjects();
    bulletsToDelete->release();//release

不過要注意的是,實(shí)際游戲如果只是簡單的檢測(cè)矩形區(qū)域,那么可能會(huì)出現(xiàn)子彈從敵機(jī)身邊掠過,而敵機(jī)卻掛了的情況,這不科學(xué)??!這是因?yàn)閿硻C(jī)兩側(cè)的透明區(qū)域過大了,碰撞檢測(cè)的是整個(gè)PNG圖的大小,不知道這個(gè)圖上哪些點(diǎn)有代表著飛機(jī)。

所以要根據(jù)游戲的實(shí)際情況來調(diào)整精靈矩形區(qū)域的大小以達(dá)到較好的游戲體驗(yàn)。

效果圖


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)