碰撞檢測(cè)是整個(gè)游戲的重頭戲,沒有它,子彈和敵機(jī)只能是路人。。。雖然很重要,但實(shí)現(xiàn)起來確是很簡單。
每個(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)用就可以了。
那我們每幀內(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ū)域是否有相交,有即碰撞。
這里以生命值最大的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)。
效果圖
更多建議: