碰撞檢測是整個游戲的重頭戲,沒有它,子彈和敵機只能是路人。。。雖然很重要,但實現(xiàn)起來確是很簡單。
每個從CCObject繼承的類都包含了一個update函數(shù),它是一個內(nèi)聯(lián)虛函數(shù),執(zhí)行頻率為每幀調(diào)用一次。
原型:
virtual CCObject::update(float dt);
開啟方式:
this->scheduleUpdate();
關(guān)閉方式:
this->unscheduleUpdate();
有了這個update函數(shù),我們就可以在GameLayer中對它進行重載,把我們每幀內(nèi)要執(zhí)行的動作放到update中,進行調(diào)用就可以了。
那我們每幀內(nèi)要做什么事呢?
我們先看一下游戲是什么?動畫?其實不過是一張張快速變換的圖片。比如我們設(shè)置60FPS,那么游戲就是一秒鐘閃過60張圖片,由于人眼的視覺殘留效應導致看起來像是動畫,因此游戲中的每一個動作我們可以認為是高速變化的靜態(tài)的圖片,而這個圖片是以幀為單位。
所以我們可以在每一幀內(nèi)進行碰撞檢測。
原理:
主角飛機是一個精靈,也就是一張帶alpha通道的PNG圖,子彈也是,敵機同樣也是,它們都是一塊矩形區(qū)域,即便有的地方是透明的。所以碰撞檢測就是在每一幀內(nèi)判斷多個不同類型矩形區(qū)域是否有相交,有即碰撞。
這里以生命值最大的Enemy3來做示例。而敵機和主角的碰撞是一樣的道理。主角的爆炸效果也是采用幀動畫,和敵機爆炸是一致的,但是要注意,主角飛機一旦爆炸,要記得StopShoot。
CCArray* bulletsToDelete=CCArray::create();//創(chuàng)建一個CCArray,用以存放待刪除的子彈,也就是此幀中被檢測到碰撞的子彈
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)建一個CCArray,用以存放待刪除的敵機,也就是此子彈擊中的敵機
enemy3sToDelete->retain();//調(diào)用retain
CCARRAY_FOREACH(this->enemyLayer->m_pAllEnemy3,et)//遍歷所有敵機
{
Enemy* enemy3=(Enemy*)et;
if (CCRect::CCRectIntersectsRect(bullet->boundingBox(),enemy3->getBoundingBox()))//檢測碰撞,即矩形區(qū)域是否相交
{
//如果life>1,移除bullet
if (enemy3->getLife()>1)//因為Enemy3設(shè)置了生命值為5
{
enemy3->loseLife();
bulletsToDelete->addObject(bullet);//把待刪除子彈放入CCArray
}
//如果life==1,移除enemy3
else if(enemy3->getLife()==1)//只剩一條命的時候,再碰撞就掛掉了
{
enemy3->loseLife();
bulletsToDelete->addObject(bullet);//把待刪除子彈放入CCArray
enemy3sToDelete->addObject(enemy3);//把待刪除敵機放入CCArray
score+=ENEMY3_SCORE;
this->controlLayer->updateScore(score);
}
//此時處在敵機爆炸動畫階段,敵機未消失,子彈還有打到的機會,所以不進行檢測
else ;
}
}
CCARRAY_FOREACH(enemy3sToDelete,et)//遍歷所有此幀中碰撞死亡的敵機,必須是死亡
{
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
不過要注意的是,實際游戲如果只是簡單的檢測矩形區(qū)域,那么可能會出現(xiàn)子彈從敵機身邊掠過,而敵機卻掛了的情況,這不科學??!這是因為敵機兩側(cè)的透明區(qū)域過大了,碰撞檢測的是整個PNG圖的大小,不知道這個圖上哪些點有代表著飛機。
所以要根據(jù)游戲的實際情況來調(diào)整精靈矩形區(qū)域的大小以達到較好的游戲體驗。
效果圖
更多建議: