cocos2dx碰撞检测

2015年02月01日 14:10 0 点赞 0 评论 更新于 2025-11-21 15:56

在Cocos2d-x开发过程中,碰撞检测是一个常见的需求。那么,Cocos2d-x的碰撞检测是如何实现的呢?下面我们将详细介绍具体的实现过程。

场景假设

假设场景中有多个敌人和子弹,子弹可以击中敌人,并且在碰撞发生后,子弹和敌人都会消失。

实现步骤

1. 追踪敌人和子弹

为了区分敌人和子弹,我们可以为这两种物体添加标签(tag)。由于CCSprite继承自CCNode,已经具备setTaggetTag方法,因此我们可以通过这种方式来区分不同的精灵。给敌人添加tag = 1,给子弹添加tag = 2

HelloWorldScene.h中添加两个成员对象,分别用于存储敌人和子弹:

protected:
cocos2d::CCArray *_targets;
cocos2d::CCArray *_projectiles;

在Cocos2d-x中,需要在构造函数中初始化这两个变量,在init()函数中进行内存分配,在析构函数中释放内存:

// 构造函数
HelloWorld::HelloWorld()
:_targets(NULL)
,_projectiles(NULL)
{
}

// 初始化
void HelloWorld::init() {
_targets = new CCArray;
_projectiles = new CCArray;
}

// 析构函数
HelloWorld::~HelloWorld()
{
if (_targets)
{
_targets->release();
_targets = NULL;
}
if (_projectiles)
{
_projectiles->release();
_projectiles = NULL;
}
// cpp不需要调用super释放,虚析构函数将会做这些事
}

2. 添加敌人和子弹到数组

添加敌人

修改addTarget()函数,将新的敌人添加到targets数组中,并将其标签设置为1:

// 添加到数组中
target->setTag(1);
_targets->addObject(target);

添加子弹

修改ccTouchesEnded()函数,将新的子弹添加到_projectiles数组中,并将其标签设置为2:

// 添加到_projectiles数组中
projectile->setTag(2);
_projectiles->addObject(projectile);

3. 移除精灵

修改spriteMoveFinished()函数,从相应的数组中移除一些精灵:

void HelloWorld::spriteMoveFinished(CCNode* sender)
{
CCSprite *sprite = (CCSprite *)sender;
this->removeChild(sprite, true);
if (sprite->getTag() == 1) // target
{
_targets->removeObject(sprite);
}
else if (sprite->getTag() == 2) // projectile
{
_projectiles->removeObject(sprite);
}
}

4. 碰撞检测

update()函数会每帧执行一次,通常用于检测碰撞并移除发生碰撞的子弹和敌人。在HelloWorldScene.h中声明该函数,在HelloWorldScene.cpp中定义:

void HelloWorld::update(float dt)
{
CCArray *projectilesToDelete = new CCArray;
CCArray* targetsToDelete = new CCArray;
CCObject* it = NULL;
CCObject* jt = NULL;
CCARRAY_FOREACH(_projectiles, it)
{
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_FOREACH(_targets, jt)
{
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 (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);
}
CCARRAY_FOREACH(projectilesToDelete, it)
{
CCSprite* projectile = dynamic_cast<CCSprite*>(it);
_projectiles->removeObject(projectile);
this->removeChild(projectile, true);
}
projectilesToDelete->release();
targetsToDelete->release();
}

5. 调用update()函数

最后,将update()函数添加到计时器中,使其每帧被调用一次,通常在onEnter()函数中添加以下代码:

void HelloWorld::onEnter()
{
CCLayer::onEnter();
this->schedule( schedule_selector(HelloWorld::update) );
}

通过以上步骤,一个简单的碰撞检测模型就建立好了。

作者信息

feifeila

feifeila

共发布了 3994 篇文章