现在我们的英雄能发射子弹了,但这些子弹只是空架子,怎么才能让子弹挂掉敌人呢?
在这一章,我们将介绍如何实现碰撞检测。
首先,我们需要对子弹和敌人进行记录。
在这个游戏里,我们为子弹和敌人这两种不同的精灵添加标签好区别它们。当tag=1时表示是敌人,当tag=2时表示是子弹。由于才CCNODE里已经存在m_nTag这个成语变量,并且setTag()和getTag()这两个方法引擎已经实现好了,我们可以直接使用它。
在HelloWorldScene.h文件里添加以下两个变量,这两个变量是分别用来存储(即上文说到底记录)子弹和敌人的。
cocos2d::CCArray *_targets;
cocos2d::CCArray *_projectiles;
同时还有构造函数和析构函数
HelloWorld();
~HelloWorld();
在HelloWorldScene.cpp文件中,在构造函数中初始化它们,并在析构函数里释放。
HelloWorld::HelloWorld()
{
_targets = new CCArray();
_targets->retain();
_projectiles = new CCArray();
_projectiles->retain();
}
HelloWorld::~HelloWorld()
{
_targets->release();
_targets = NULL;
_projectiles->release();
_projectiles = NULL;
}
现在修改addTarget()函数,把敌人添加到_targets数组中,并把敌人设置标签为1。
// 设置敌人标签为1
target->setTag(1);
// 把精灵添加进缓存
_targets->addObject(target);
// 把敌人精灵添加到HelloWorld图层
修改ccTouchBegan函数,把子弹添加到_projectiles数组中,并把子弹设置标签为2。
// 设置子弹标签为2
projectile->setTag(2);
// 把精灵添加进缓存
_projectiles->addObject(projectile);
然后,照下面的写法修改spriteMoveFinished函数,我们在这里从对应的数组移除精灵。
// 移除精灵
void HelloWorld::spriteMoveFinished(CCNode *sender )
{
CCSprite *sprite = (CCSprite *)sender;
this->removeChild(sprite, true);
if (sprite->getTag() ==1)
{
// 如果该精灵的标签是1,从_targets数组移除该精灵
_targets->removeObject(sprite, true);
}else if (sprite->getTag() ==2)
{
// 如果该精灵的标签是2,从_projectiles数组移除该精灵
_projectiles->removeObject(sprite, true);
}
}
下边的update()函数用来检测每一帧的碰撞,移除发生碰撞的子弹和敌人。
在HelloWorldScene.h声明定义该函数
void update(float dt);
并在HelloWorldScene.cpp文件中实现它。
void HelloWorld::update( float dt )
{
// 存放发生碰撞的子弹
CCArray *projectilesToDelete = new CCArray;
projectilesToDelete->retain();
CCObject* it = NULL;
CCObject* jt = NULL;
// 遍历所有子弹,检测每个子弹是否与敌人发生碰撞
CCARRAY_FOREACH(_projectiles, it)
{
// 将取出的对象强制转换为CCSprite
CCSprite *projectile = dynamic_cast<CCSprite*>(it);
// 得到当前子弹现在所占区域
CCRect projectileRect = CCRectMake(
projectile->getPosition().x - (projectile->getContentSize().width/2),
projectile->getPosition().y - (projectile->getContentSize().height/2),
projectile->getContentSize().width,
projectile->getContentSize().height);
// 存放发生碰撞的敌人
CCArray* targetsToDelete =new CCArray;
targetsToDelete->retain();
// 遍历_targets中的所有对象,每次都把对象放进jt
CCARRAY_FOREACH(_targets, jt)
{
// 将取出的对象强制转换为CCSprite
CCSprite *target = dynamic_cast<CCSprite*>(jt);
// 得到当前敌人现在所占区域
CCRect targetRect = CCRectMake(
target->getPosition().x - (target->getContentSize().width/2),
target->getPosition().y - (target->getContentSize().height/2),
target->getContentSize().width,
target->getContentSize().height);
// if (CCRect::CCRectIntersectsRect(projectileRect, targetRect))
// 如果projectileRect区域与targetRect区域发生交集,将子弹和敌人放进待删除数组
if (projectileRect.intersectsRect(targetRect))
{
targetsToDelete->addObject(target);
projectilesToDelete->addObject(projectile);
}
}
// 遍历待删除敌人数组,将所有待删除敌人删除
CCARRAY_FOREACH(targetsToDelete, jt)
{
CCSprite *target = dynamic_cast<CCSprite*>(jt);
_targets->removeObject(target);
this->removeChild(target, true);
}
// 释放敌人待删除数组
targetsToDelete->release();
}
// 遍历待删除子弹数组,将所有待删除子弹删除
CCARRAY_FOREACH(projectilesToDelete, it)
{
CCSprite* projectile = dynamic_cast<CCSprite*>(it);
_projectiles->removeObject(projectile);
this->removeChild(projectile, true);
}
// 释放子弹待删除数组
projectilesToDelete->release();
}
OK,最后我们要把update函数加入到schedule里让它每一帧都进行碰撞检测,我们把这句话加进init函数中。
// 每一帧都进行碰撞检测
this->schedule(schedule_selector(HelloWorld::update));
编译并执行项目,怎么高兴就这么开枪,这时,哈哈,敌人一个一个都被干掉了。
附本章源码下载:http://download.csdn.net/detail/lpkkk/4997341
文章所写的东西只是我自己的理解,如果哪里出现错误,敬请斧正。
您可以留言、微博私聊我或Email我
我的微博:http://weibo.com/u/2007282737
我的Email:pengkailiao@gmail.com