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

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

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. [译]Stairway to Integration Services Level 3 - 增量导入数据

    让我们打开之前的项目:My_First_SSIS_Project_After_Step_2.zip 之前项目中我们已经向dbo.contact 导入了19972行,如果再次执行包会重复导入,让我们来解 ...

  2. linux shell: 搜索字符串,剔除包含特定字符的行

    搜索代码中出现CONFIG_BOOTARGS的行,但又不希望有#define和#undef, 暂时不知带如何直接用一个语句做到,因此用了如下三个语句. find . -type f | xargs g ...

  3. 类似jquery的一个demo

    通过以下的demo,可以大体知道jquery的一些组织结构以及一些实现方法. 实际上jquery就是一个全局变量,只是在这个变量上添加了各种属性和方法. 首先我们要理解什么是匿名函数自执行,简单点就是 ...

  4. Python学习之路——类

    类: 类是将抽象的实物进行的划分. 在现实世界中如果我们将: 人类包含:男人.女人.孩子.老人等动物类包含:小猫.小狗.小兔子等 在代码世界中我也可以分类,例如将相同功能的代码放到一起,这就是分类. ...

  5. shell学习之常用命令总结

    1.find命令 主要用途:主要用来做文件查找. 使用方法:查找文件的方式可以基于:文件名,文件时间属性,文件的所有者和组,文件权限属性,文件类型属性,文件大小,另外可以指定 查找目录的深度,排除指定 ...

  6. Archive for required library: ‘WebContent/WEB-INF/lib/xxx.jar cannot&n

    今天导入一个项目到eclipse,出现感叹号,而且报1. Archive for required library: ‘WebContent/WEB-INF/lib/xxxxx.jar cannot ...

  7. jsp中forward和redirect的区别(转)

    一.调用方式 我们知道,在servlet中调用转发.重定向的语句如下: request.getRequestDispatcher("new.jsp").forward(reques ...

  8. i++和++i以及左值,右值

    左值(LValue)和右值(RValue)的一个快捷记法是赋值运算,左值是赋值运算左边的值,右值就是右边(=,=废话).例如: int a = 5; a就是左值,5就是右值. 当然,如果真是这么个含义 ...

  9. Dining(最大流)

    Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11844   Accepted: 5444 Descripti ...

  10. switch case ,while, do while,enum

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace C_编辑 ...