在cocos2dx开发时我们会遇到cocos2dx碰撞检测,那么cocos2dx碰撞检测是怎样实现的呢?现在我们就来看具体的实现过程。

在此场景中,我们假设有很多敌人和子弹,其中子弹可以击中敌人,并且碰撞后子弹和敌人都会随之消失。

首先,我们需要去追踪这些敌人和子弹。
我们可以为这两种物体添加tag,在这里我们给敌人添加tag=1,给子弹添加tag=2,。因为CCSprite继承自CCNode,因为已经有了setTag和getTag方法;我们可以通过这种方式来区分不同的精灵。
添加两个成员对象在HelloWorldScene.h中。用来分别存储存在的敌人和子弹。
  1. [cpp] view plaincopy
  2. protected:
  3. cocos2d::CCArray *_targets;
  4. cocos2d::CCArray *_projectiles;
在cocos2dx中,在构造函数中初始化这两个变量,在init()函数中new,在析构函数中release。
  1. [cpp] view plaincopy
  2. // 初始化
  3. _targets = new CCArray;
  4. _projectiles = new CCArray;
  5. HelloWorld::~HelloWorld()
  6. {
  7. if (_targets)
  8. {
  9. _targets->release();
  10. _targets = NULL;
  11. }
  12. if (_projectiles)
  13. {
  14. _projectiles->release();
  15. _projectiles = NULL;
  16. }
  17. // cpp不需要调用super释放,虚析构函数将会做这些事
  18. }
  19. HelloWorld::HelloWorld()
  20. :_targets(NULL)
  21. ,_projectiles(NULL)
  22. {
  23. }
现在更改addTarget()来添加一个新的敌人到targets数组中,并且把它的tag设置为1.
  1. [cpp] view plaincopy
  2. // 添加到数组中
  3. target->setTag(1);
  4. _targets->addObject(target);
更改一下ccTouchesEnded()来添加一个新的子弹到bullets数组中,并且设置它的tag为2.
  1. [cpp] view plaincopy
  2. // 添加到_projectiles数组中
  3. projectile->setTag(2);
  4. _projectiles->addObject(projectile);
接下来,更改如下的spriteMoveFinished()函数。这里我们将从相应的数组中移除一些精灵。
  1. [cpp] view plaincopy
  2. void HelloWorld::spriteMoveFinished(CCNode* sender)
  3. {
  4. CCSprite *sprite = (CCSprite *)sender;
  5. this->removeChild(sprite, true);
  6. if (sprite->getTag() == 1)  // target
  7. {
  8. _targets->removeObject(sprite);
  9. }
  10. else if (sprite->getTag() == 2) // projectile
  11. {
  12. _projectiles->removeObject(sprite);
  13. }
  14. }
下面的函数update()将会每帧被执行到一次,一般用来检测碰撞检测,可以移除掉碰撞的子弹和敌人。
在HelloWorldScene.h中声明它,在HelloWorldScene.cpp.定义它。
  1. [cpp] view plaincopy
  2. void HelloWorld::update(float dt)
  3. {
  4. CCArray *projectilesToDelete = new CCArray;
  5. CCArray* targetsToDelete =new CCArray;
  6. CCObject* it = NULL;
  7. CCObject* jt = NULL;
  8. CCARRAY_FOREACH(_bullet, it)
  9. {
  10. CCSprite *projectile = dynamic_cast<CCSprite*>(it);
  11. CCRect projectileRect = CCRectMake(
  12. projectile->getPosition().x - (projectile->getContentSize().width/2),
  13. projectile->getPosition().y - (projectile->getContentSize().height/2),
  14. projectile->getContentSize().width,
  15. projectile->getContentSize().height);
  16. CCARRAY_FOREACH(_target, jt)
  17. {
  18. CCSprite *target = dynamic_cast<CCSprite*>(jt);
  19. CCRect targetRect = CCRectMake(
  20. target->getPosition().x - (target->getContentSize().width/2),
  21. target->getPosition().y - (target->getContentSize().height/2),
  22. target->getContentSize().width,
  23. target->getContentSize().height);
  24. if (projectileRect.intersectsRect(targetRect))
  25. {
  26. targetsToDelete->addObject(target);
  27. projectilesToDelete->addObject(projectile);
  28. }
  29. }
  30. }
  31. CCARRAY_FOREACH(targetsToDelete, jt)
  32. {
  33. CCSprite *target = dynamic_cast<CCSprite*>(jt);
  34. _target->removeObject(target);
  35. this->removeChild(target, true);
  36. }
  37. CCARRAY_FOREACH(projectilesToDelete, it)
  38. {
  39. CCSprite* projectile = dynamic_cast<CCSprite*>(it);
  40. _bullet->removeObject(projectile);
  41. this->removeChild(projectile, true);
  42. }
  43. projectilesToDelete->release();
  44. targetsToDelete->release();
好了,最后的事情我们将要做的就是添加update()到计时器中,来让它每帧被调用一次,一般在onEnter()函数中添加此行代码。
  1. [cpp] view plaincopy
  2. void HelloWorld::onEnter()
  3. {
  4. CCLayer::onEnter();
  5. this->schedule( schedule_selector(HelloWorld::update) );
  6. }
一个简单的碰撞检测模型就建立好啦~