cocos2d x遊戲開發系列教程 坦克大戰遊戲之子彈的碰撞檢測處理
阿新 • • 發佈:2018-11-08
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!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