cocos2d-x游戏开发系列教程-坦克大战游戏之子弹的碰撞检测处理
在上篇我们加上了简单的坦克之间的碰撞检测,这篇我们继续加上子弹之间,
子弹与坦克之间的碰撞检测,对于上一篇碰撞处理不太完美的地方我们继续改进。
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游戏开发系列教程-坦克大战游戏之子弹的碰撞检测处理的更多相关文章
- cocos2d-x游戏开发系列教程-坦克大战游戏启动界面的编写
用前面介绍的方法,创建一个cocos2d-x项目,可以看到新项目内容如下图:
- cocos2d-x游戏开发系列教程-坦克大战游戏之虚拟手柄控制坦克移动
上篇显示了控制手柄,但是还不能用来控制坦克, 这篇将会讲手柄和坦克的移动结合起来. 1.先在CityScene场景中实现场景的虚函数virtual void onEnter(); onEnter在进入 ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之所有坦克之间的碰撞检测
上篇我们完成了简单的AI编写,但是各个坦克移动时之间是可以重合的, 这节课我们来完成坦克之间的碰撞检测,还是在上篇的EnemyAI中完成. 1.我先现在坦克类Tank中添加两个成员变量: CC_SYN ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之敌方坦克AI的编写
在上篇我们完成了子弹和地图碰撞的检测,在这篇我们将完成敌方坦克AI的编写. 具体思路是屏幕中保持有四个敌方坦克,然后坦克随机方向运动,并且子弹消失后1秒发射一次 1.我们新建一个敌方坦克的AI类来控制 ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之子弹和地图碰撞
上篇文章实现了坦克与地图碰撞的检测, 这篇我们继续完成子弹和地图的碰撞检测. 1.先设计一个子弹类Bullet,如下所示: class Bullet : public CCSprite { publi ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之坦克和地图碰撞的检测下
上篇我们完成了地图的信息获取和碰撞检测,这篇我们整合到程序中. 在这之前我们改造一下Tank类,使它更加模块化,共容易理解: 1.改造后的Tank类声明如下: class Tank : public ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之虚拟手柄的显示
上篇文章我们有了坦克,但是没有手柄,无法控制坦克. 1.这篇我们编写虚拟手柄来控制坦克.头文件大致内容如下: #define RES_PADDLE_LEFT "paddle/left.png ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之坦克的显示
1.先定义坦克的一些属性 class Tank : public CCSprite { public : Tank(); ~Tank(); static Tank* createTankWithTan ...
- cocos2d-x游戏开发系列教程-坦克大战游戏加载地图的编写
上节课写了关卡选择场景,那么接下来写关卡内容,先写最基本的地图的加载 我们新建一个场景类,如下所示: class CityScene : public cocos2d::CCLayer { publi ...
随机推荐
- SQL数据库语句练习题目
一. 设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教师信息表(Teacher).四个表的结构分别如表1-1的表(一)~表( ...
- ELF文件数据布局探索(1)
作为一名Linux小白,第一次看到a.out这个名字,感觉实在是奇怪,搜了一下才知道这是编译器输出的默认可执行文件名 然后vi一下,哇,各种乱码,仔细看看,发现了三个清晰的字符ELF.继续搜索, 第一 ...
- js的初始化
在项目中遇到了类似于这样的js, myinit.js文件: var wyl_01 = { tip : function(msg){ alert('i am a tip,msg:'+msg); }, t ...
- Laravel 5.1 ACL权限控制 一
请自行添加命名空间,代码下载地址 https://github.com/caoxt/learngit 1.所需要用到的数据表 users(用户表).roles(角色表).role_user(用户角色对 ...
- [LeetCode]题解(python):022-Generate Parentheses
题目来源: https://leetcode.com/problems/generate-parentheses/ 题意分析: 题目输入一个整型n,输出n对小括号配对的所有可能性.比如说,如果输入3, ...
- java.util.concurrent BlockingQueue
BlockingQueue 它实现了Queue接口.它是A BlockingQueue with one thread putting into it, and another thread taki ...
- QPushButton跑进度条(使用QSS的不同修饰来实现,其实是伪进度条)
主要用到qlineargradient,写以下CSS样式即可实现: background:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, sto ...
- filezilla Can't open data connection.
(000003)2016/7/4 9:31:42 - (not logged in) (10.61.41.57)> Connected, sending welcome message... ( ...
- Putty远程登录VMware虚拟机Linux(Ubuntu12.04)
为了不至于来回在Win7和Ubuntu12.04之间来回切换,在Win7下使用VMware9.0安装了Ubuntu12.04. 首先下载Vmware9.0虚拟机软件,下载地址为:VMware-work ...
- 手把手教你在Windows端搭建Redmine项目管理软件
1.Redmine介绍 Redmine是用Ruby开发的基于web的项目管理软件,是用ROR框架开发的一套跨平台项目管理系统,据说是源于Basecamp的ror版而来,支持多种数据库,有不少自己独特的 ...