cocos2dx打飛機項目筆記六:GameScene類和碰撞檢測 boundingbox


GameScene類雖然是占用游戲最多時間的類,但是里面的東西不是很多,最重要的就是碰撞檢測了,碰撞檢測代碼如下:

  1 void GameScene::detectionCrash()
  2 {
  3 
  4     CCArray* bulletsToDelete = CCArray::create();//創建一個CCArray,用以存放待刪除的子彈,也就是此幀中被檢測到碰撞的子彈 
  5     bulletsToDelete->retain();//必須調用retain,CCArray內部調用了autoRelease
  6     CCObject* bt,*et;
  7 
  8     CCArray* enemyToDelete = CCArray::create();//創建一個CCArray,用以存放待刪除的敵機,也就是此子彈擊中的敵機
  9     enemyToDelete->retain();//調用retain  
 10 
 11     CCRect rectHero = this->heroLayer->getHero()->boundingBox();
 12     float x = rectHero.origin.x + rectHero.size.width * 0.3;
 13     float y = rectHero.origin.y + rectHero.size.height * 0.4;
 14     float width = rectHero.size.width * 0.3;
 15     float height = rectHero.size.height * 0.6;
 16     CCRect rect_HeroForCrash = CCRectMake(x, y, width, height);
 17 
 18     //檢測敵機和hero是否相撞
 19     CCARRAY_FOREACH(this->enemyLayer->m_enemys,et)//遍歷所有敵機
 20     {
 21         //break;
 22 
 23         Enemy* enemy = (Enemy*)et;
 24         if (enemy->getLife() == 0)
 25         {
 26             break;
 27         }
 28 
 29         
 30     //    CCPoint rect1 = this->heroLayer->getHero()->getPosition();
 31         //boundingBox 獲取的是相對於父節點的左下角為原點的一個rect,所以要比較兩個精靈是否相交,他們的父節點的坐標原點和大小應該一樣
 32         if(enemy->boundingBox().intersectsRect(rect_HeroForCrash)) 
 33         {
 34 
 35             this->heroLayer->setIsHeroLive(false);
 36             this->heroLayer->setHeroLifes(this->heroLayer->getHeroLifes() - 1);
 37 
 38             enemyLayer->stopTakeEnemy();
 39             enemyLayer->bomb(enemy);
 40             enemyLayer->removeAllEnmeys();
 41 
 42             SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
 43 
 44             int tempHightScore = GameScene::getHightestScore();
 45             if (this->m_totalScore > tempHightScore)
 46             {
 47                 GameScene::saveHightestScore(this->m_totalScore);
 48             }
 49 
 50             char life[64];
 51             sprintf(life, "%d", this->heroLayer->getHeroLifes());
 52             CCLabelTTF* lbLife = (CCLabelTTF*)this->getChildByTag(tagOfLife);
 53             lbLife->setString(life);
 54 
 55 
 56             this->heroLayer->heroBomb(0.1f);
 57             if (this->heroLayer->getHeroLifes() == 0)
 58             {
 59 
 60                 this->scheduleOnce(schedule_selector(GameScene::gameOverCallback), 2.0f);
 61             } 
 62             else
 63             {
 64                 this->scheduleOnce(schedule_selector(GameScene::newLife), 2.0f);
 65             }
 66 
 67             return;
 68         }
 69     }
 70 
 71     //檢測敵機和子彈是否相撞
 72     CCARRAY_FOREACH(this->heroLayer->getBullets()->m_bullets,bt)//遍歷所有子彈    
 73     {    
 74         CCSprite* bullet = (CCSprite*)bt;
 75 
 76         CCARRAY_FOREACH(this->enemyLayer->m_enemys,et)//遍歷所有敵機
 77         {
 78             Enemy* enemy3 = (Enemy*)et;
 79             
 80 
 81             if(enemy3->boundingBox().intersectsRect(bullet->boundingBox())) 
 82             {
 83 
 84                 if (enemy3->getLife() > 1)
 85                 {
 86                     enemy3->loseLife();
 87                     bulletsToDelete->addObject(bullet);//把待刪除子彈放入CCArray  
 88                 }
 89                 else if (enemy3->getLife() == 1)
 90                 {
 91                     enemy3->loseLife();
 92                     bulletsToDelete->addObject(bullet);//把待刪除子彈放入CCArray  
 93                     enemyToDelete->addObject(enemy3);//把待刪除敵機放入CCArray 
 94 
 95                     this->m_totalScore += enemy3->getScore();
 96 
 97                     char str1[20];
 98                     sprintf(str1, "%d",(int)this->m_totalScore);
 99 
100                     CCLabelTTF* label1 = (CCLabelTTF*)this->getChildByTag(tagOfScore);
101 
102                     label1->setString(str1);
103                 }
104                 
105             }
106         }
107 
108     }
109 
110     CCARRAY_FOREACH(enemyToDelete,et)//遍歷所有此幀中碰撞死亡的敵機,必須是死亡
111     {
112         CCSprite* enemy3 = (CCSprite*)et;
113         this->enemyLayer->bomb(enemy3);//執行爆炸
114     }
115     enemyToDelete->release();//release
116 
117     CCARRAY_FOREACH(bulletsToDelete,bt)//遍歷所有此幀中碰撞的子彈
118     {
119         CCSprite* bullet = (CCSprite*)bt;
120         this->heroLayer->getBullets()->removeBullet(bullet);//執行移除
121     }
122     bulletsToDelete->release();//release
123 }

還記得之前說過 boundingbox 方法是獲取節點以父節點左下角為原點的一個矩形吧,該矩形的大小就是節點各種變形后的大小,矩形的左下角坐標就是節點變形后的左下角坐標

bullet是加到 ccspriteBatchNode 上的,ccspriteBatchNode是加到 BulletLayer上面的,ccspriteBatchNode和bulletLayer都是鋪滿屏幕的。所以子彈調用 boundingbox 獲得的矩形是以屏幕左下角為原點的。敵機的原理也是如此。hero是直接加到 herolayer 上的,父節點同樣是鋪滿屏幕的,所以他們的父節點的左下角的坐標都一樣的,這就是通過 boundingbox 檢測他們是否碰撞的前提。

 

有些紋理周圍有比較大的空白地方,這就會造成兩個節點看起來還沒有接觸就會發生碰撞,這就需要對碰撞進行更精確的判斷,可以通過什么像素判斷法之類的。我這里采取最簡單的處理方法,就是通過節點的boundingbox獲取到一個rect,然后對這個rect加工一下:

1     CCRect rectHero = this->heroLayer->getHero()->boundingBox();
2     float x = rectHero.origin.x + rectHero.size.width * 0.3;
3     float y = rectHero.origin.y + rectHero.size.height * 0.4;
4     float width = rectHero.size.width * 0.3;
5     float height = rectHero.size.height * 0.6;
6     CCRect rect_HeroForCrash = CCRectMake(x, y, width, height);

這樣子可以獲取節點 boundingbox 里面的某一部分來作為碰撞的檢測部分

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM