在上篇我们加上了简单的坦克之间的碰撞检测,这篇我们继续加上子弹之间,

子弹与坦克之间的碰撞检测,对于上一篇碰撞处理不太完美的地方我们继续改进。

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

cocos2d-x游戏开发系列教程-坦克大战游戏之子弹的碰撞检测处理的更多相关文章

  1. cocos2d-x游戏开发系列教程-坦克大战游戏启动界面的编写

    用前面介绍的方法,创建一个cocos2d-x项目,可以看到新项目内容如下图:

  2. cocos2d-x游戏开发系列教程-坦克大战游戏之虚拟手柄控制坦克移动

    上篇显示了控制手柄,但是还不能用来控制坦克, 这篇将会讲手柄和坦克的移动结合起来. 1.先在CityScene场景中实现场景的虚函数virtual void onEnter(); onEnter在进入 ...

  3. cocos2d-x游戏开发系列教程-坦克大战游戏之所有坦克之间的碰撞检测

    上篇我们完成了简单的AI编写,但是各个坦克移动时之间是可以重合的, 这节课我们来完成坦克之间的碰撞检测,还是在上篇的EnemyAI中完成. 1.我先现在坦克类Tank中添加两个成员变量: CC_SYN ...

  4. cocos2d-x游戏开发系列教程-坦克大战游戏之敌方坦克AI的编写

    在上篇我们完成了子弹和地图碰撞的检测,在这篇我们将完成敌方坦克AI的编写. 具体思路是屏幕中保持有四个敌方坦克,然后坦克随机方向运动,并且子弹消失后1秒发射一次 1.我们新建一个敌方坦克的AI类来控制 ...

  5. cocos2d-x游戏开发系列教程-坦克大战游戏之子弹和地图碰撞

    上篇文章实现了坦克与地图碰撞的检测, 这篇我们继续完成子弹和地图的碰撞检测. 1.先设计一个子弹类Bullet,如下所示: class Bullet : public CCSprite { publi ...

  6. cocos2d-x游戏开发系列教程-坦克大战游戏之坦克和地图碰撞的检测下

    上篇我们完成了地图的信息获取和碰撞检测,这篇我们整合到程序中. 在这之前我们改造一下Tank类,使它更加模块化,共容易理解: 1.改造后的Tank类声明如下: class Tank : public ...

  7. cocos2d-x游戏开发系列教程-坦克大战游戏之虚拟手柄的显示

    上篇文章我们有了坦克,但是没有手柄,无法控制坦克. 1.这篇我们编写虚拟手柄来控制坦克.头文件大致内容如下: #define RES_PADDLE_LEFT "paddle/left.png ...

  8. cocos2d-x游戏开发系列教程-坦克大战游戏之坦克的显示

    1.先定义坦克的一些属性 class Tank : public CCSprite { public : Tank(); ~Tank(); static Tank* createTankWithTan ...

  9. cocos2d-x游戏开发系列教程-坦克大战游戏加载地图的编写

    上节课写了关卡选择场景,那么接下来写关卡内容,先写最基本的地图的加载 我们新建一个场景类,如下所示: class CityScene : public cocos2d::CCLayer { publi ...

随机推荐

  1. 新到的Mac配置Java开发环境

    今天Mac到手,需要配置一些用到的开发环境,在这里做一些纪录. 1. 下载Eclipse,地址:http://www.eclipse.org/downloads/,因为个人需求,所以下载的是Java ...

  2. CAN总线与RS485的比较

    CAN总线与RS485的比较 http://blog.csdn.net/reille/article/details/6135546 can总线与485总线有什么区别?  http://blog.16 ...

  3. BZOJ 1880: [Sdoi2009]Elaxia的路线( 最短路 + dp )

    找出同时在他们最短路上的边(dijkstra + dfs), 组成新图, 新图DAG的最长路就是答案...因为两人走同一条路但是不同方向也可以, 所以要把一种一个的s,t换一下再更新一次答案 ---- ...

  4. jQuery(二)

    table 全选.反选.清除 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  5. poj 1150 The Last Non-zero Digit

    /** 大意: 求A(n,m)的结果中从左到右第一个非零数 思路: 0是由2*5的得到的,所以将n!中的2,5约掉可得(2的数目比5多,最后再考虑进去即可) 那n!中2 的个数怎么求呢? int ge ...

  6. Python IDLE快捷键

    编辑状态时:Ctrl + [ .Ctrl + ] 缩进代码Alt+3 Alt+4 注释.取消注释代码行Alt+5 Alt+6 切换缩进方式 空格<=>TabAlt+/ 单词完成,只要文中出 ...

  7. (IOS)N duplicate symbols for architecture i386

    Xcode编译时的error,出现此情况的汇总引用如下: 1.可能存在两个main入口: 2.导入的.h文件可能误写为.m: 3.两文件间可能存在重复定义的全局变量名: 4.使用#include导入文 ...

  8. (IOS)CoreLocation 和 MapKit 的应用

    CoreLocation是控制GPS硬件获取地理坐标信息的系统类库,而MapKit是系统地图的工具包,将两者结合使用可以实现不同的地图功能. 1.CoreLocation 在CoreLocation中 ...

  9. Linux学习:netstat命令

    Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态等.对于开发来说,很多时候用于查看端口占用情况. 执行netstat命令,其输出结果可以分成两部分: 1)一是“Active ...

  10. bash: ./configure: 权限不够

    linux下运行一个文件时 提示权限不够,说明这个文件没有可执行权限 我们可以在属性里面手动为这个文件加上可执行权限也可以使用命令的方式 命令方式: 例如:   bash: ./configure: ...