1. 程式人生 > >cocos2d x遊戲開發系列教程 坦克大戰遊戲之子彈的碰撞檢測處理

cocos2d x遊戲開發系列教程 坦克大戰遊戲之子彈的碰撞檢測處理

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

在上篇我們加上了簡單的坦克之間的碰撞檢測,這篇我們繼續加上子彈之間,

子彈與坦克之間的碰撞檢測,對於上一篇碰撞處理不太完美的地方我們繼續改進。

1.子彈之間的碰撞

 //玩家子彈和敵方子彈之間的碰撞
 CCObject* pObj; CCARRAY_FOREACH(mEnemyTanks, pObj) {  Bullet* enemyBullet = ((Tank*)pObj)->getBullet();  if (playerBullet->getFlyState() && enemyBullet->getFlyState())  {   if (IsRectIntersect(playerBullet->getMovedRect(), enemyBullet->getMovedRect()))   {    enemyBullet->stopFire();    playerBullet->stopFire();    break
;   }  } }

我們通過玩家子彈playerBullet與敵人子彈之間的碰撞檢測,如果碰撞了呼叫了子彈的stopFire函式。


2.如果子彈相撞了,當然是子彈直接消失,然後設定子彈飛行狀態為false,我們來看看stopFire的函式具體實現:

bool Bullet::stopFire(){ if (mFlyState == true) {  mFlyState = false;  setVisible(false);  unscheduleUpdate();  return
true; } return false;}
其中mFlyState表示飛行狀態,然後設定了不可見,取消了定時器,不再做子彈運動的計算。


3.我們再新增玩家子彈和敵人坦克的碰撞:

 //玩家子彈和敵方坦克的碰撞 CCARRAY_FOREACH(mEnemyTanks, pObj) {  if (playerBullet->getFlyState())  {   Tank* enemyTank = (Tank*)pObj;   if (IsRectIntersect(playerBullet->getMovedRect(), enemyTank->getMovedRect()))   {    mEnemyTanks->removeObject(pObj);    enemyTank->remove();    playerBullet->stopFire();    break;   }  } }
可以看到檢測碰撞後從敵人坦克陣列中移除了坦克物件,然後呼叫了坦克的remove命令,

來釋放此坦克物件佔用的記憶體,然後呼叫了玩家子彈的stopFire。


4.下面看看坦克物件的remove實現:

void Tank::remove(){ mTileMapInfo->getTileMap()->removeChild(this);}

他簡單的呼叫了地圖的removeChild函式,將自己從地圖中移除了。


5.最後看看敵人子彈和玩家坦克的碰撞處理:

 //敵人子彈和玩家的碰撞 CCARRAY_FOREACH(mEnemyTanks, pObj) {  Bullet* enemyBullet = ((Tank*)pObj)->getBullet();  if (enemyBullet->getFlyState())  {   if (IsRectIntersect(enemyBullet->getMovedRect(), mTank->getMovedRect()))   {    mTank->setVisible(false);    enemyBullet->stopFire();    break;   }  } }
發生碰撞後,簡單的將玩家坦克設定為不可見,然後停止敵人子彈開火。


6.碰撞函式基本上全部修改完畢,看看最後碰撞函式整體:

void EnemyAI::collisionTest(){ Bullet* playerBullet = mTank->getBullet(); //坦克之間的碰撞 CCArray* ccTmpArray = CCArray::create(); ccTmpArray->addObjectsFromArray(mEnemyTanks); ccTmpArray->addObject(mTank); CCObject* pObjSrc; CCARRAY_FOREACH(ccTmpArray, pObjSrc) {  Tank* tankSrc = (Tank*)pObjSrc;  CCObject* pObjdst;  CCARRAY_FOREACH(ccTmpArray, pObjdst)  {   Tank* tankDst = (Tank*)pObjdst;   if (tankSrc != tankDst)   {    CCRect rectDst;    if (ccTmpArray->indexOfObject(pObjSrc) > ccTmpArray->indexOfObject(pObjdst))    {     //之前的坦克已經確定了要移動的位置     rectDst = tankDst->getMovedRect();    }    else    {     //還沒有確定要移動的坦克     rectDst = tankDst->boundingBox();    }    if (IsRectIntersect(tankSrc->getMovedRect(), rectDst))    {     //確保在移動之前沒有重合     if (!IsRectIntersect(tankSrc->boundingBox(), rectDst))     {      tankSrc->setBlock(true);     }    }   }  } } //玩家子彈和敵方子彈之間的碰撞 CCObject* pObj; CCARRAY_FOREACH(mEnemyTanks, pObj) {  Bullet* enemyBullet = ((Tank*)pObj)->getBullet();  if (playerBullet->getFlyState() && enemyBullet->getFlyState())  {   if (IsRectIntersect(playerBullet->getMovedRect(), enemyBullet->getMovedRect()))   {    enemyBullet->stopFire();    playerBullet->stopFire();    break;   }  } } //玩家子彈和敵方坦克的碰撞 CCARRAY_FOREACH(mEnemyTanks, pObj) {  if (playerBullet->getFlyState())  {   Tank* enemyTank = (Tank*)pObj;   if (IsRectIntersect(playerBullet->getMovedRect(), enemyTank->getMovedRect()))   {    mEnemyTanks->removeObject(pObj);    enemyTank->remove();    playerBullet->stopFire();    break;   }  } } //敵人子彈和玩家的碰撞 CCARRAY_FOREACH(mEnemyTanks, pObj) {  Bullet* enemyBullet = ((Tank*)pObj)->getBullet();  if (enemyBullet->getFlyState())  {   if (IsRectIntersect(enemyBullet->getMovedRect(), mTank->getMovedRect()))   {    mTank->setVisible(false);    enemyBullet->stopFire();    break;   }  } }}

可以看到上面的坦克和坦克之間的碰撞檢測,相比較上一篇中的坦克間的碰撞檢測更加精確,

解決了上篇文章中坦克之間可能卡死的狀況。


7.對於坦克行為的控制也做了少許修改:

void EnemyAI::tankAction(float delta){ CCObject* pObj; CCARRAY_FOREACH(mEnemyTanks, pObj) {  Tank* tank = (Tank*)pObj;  //坦克按照上次的方向一直往前走  int Rotation = tank->getRotation();  tank->command((enumOrder)(Rotation / 90 + 1));  //坦克每隔一秒開一次火  tank->setBulletDelta(tank->getBulletDelta() + delta);  if (tank->getBulletDelta() > 1)  {   //開火後,如果子彈在飛行中,歸零計時   if (tank->command(cmdFire))   {    tank->setBulletDelta(0.0);   }  } } //檢測坦克之間的碰撞 collisionTest(); move();}
上面函式在控制玩坦克行為後,檢測了是否發生了碰撞,最後才呼叫move來移動坦克位置。

看看move函式的實現:

void EnemyAI::move(){ mTank->move(); CCObject* pObj; CCARRAY_FOREACH(mEnemyTanks, pObj) {  Tank* tank = (Tank*)pObj;  //如果坦克阻塞,換個方向  if (tank->getBlock())   tank->setRotation((int)(CCRANDOM_0_1() * 3.8) * 90);  //如果上面的判斷完成後,坦克根據自己的阻塞狀態移動  tank->move(); }}
move函式在檢測了坦克是否阻塞,如果阻塞則隨機切換坦克執行方向,

然後呼叫了坦克自身的move函式移動到相應位置。


最後我們來看看執行效果:



完整程式碼下載地址:

http://download.csdn.net/detail/yincheng01/6779739

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述