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 里面的某一部分来作为碰撞的检测部分

 

posted @ 2013-12-25 16:01  仙外仙  阅读(12781)  评论(0编辑  收藏  举报