cocos2d-x 使用box2d来做碰撞检测(且仅用来做碰撞检测)

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include <Box2D/Box2D.h>
#include "cocos2d.h"
#include <list>
using std::list;

class MyContact
{
public:
  b2Fixture* fixtureA;
  b2Fixture* fixtureB;
};

// Contact listener
class MyContactListener : public b2ContactListener
{
  // Callbacks for derived classes.
  virtual void BeginContact(b2Contact* contact) 
  { 
    if (contact)
    {
      MyContact mc;
      mc.fixtureA = contact->GetFixtureA();
      mc.fixtureB = contact->GetFixtureB();

      contact_list.push_back(mc);
    }
    B2_NOT_USED(contact); 
  }
  virtual void EndContact(b2Contact* contact) 
  { 
    contact_list.clear();
    B2_NOT_USED(contact); 
  }
  virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
  {
    B2_NOT_USED(contact);
    B2_NOT_USED(oldManifold);
  }
  virtual void PostSolve(const b2Contact* contact, const b2ContactImpulse* impulse)
  {
    B2_NOT_USED(contact);
    B2_NOT_USED(impulse);
  }

public:
  std::list<MyContact> contact_list;
};

class HelloWorld : public cocos2d::CCLayer
{
public:
    HelloWorld();
    ~HelloWorld();
    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    // there's no 'id' in cpp, so we recommand to return the exactly class pointer
    static cocos2d::CCScene* scene();
    
    // a selector callback
    void menuCloseCallback(CCObject* pSender);
        
    virtual void ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
    virtual void ccTouchesMoved(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
    virtual void ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
    virtual void ccTouchesCancelled(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);

    cocos2d::CCTMXLayer *baseLayer;

    // implement the "static node()" method manually
    LAYER_CREATE_FUNC(HelloWorld);

private:
  // Update per second
  void secondUpdate(float dt)  
  {  
    spawnCat();
  }
  void tick(float dt);

  // spawn a car
  void spawnCar();

  // spawn a car
  void spawnCat();

  // Sprite move over call back
  void spriteDone(cocos2d::CCNode* sender);

  // Add contact b2box for sprite
  void addBoxBodyForSprite(cocos2d::CCSprite* sprite);

  b2World* world;
  MyContactListener* contactListener; // Contact event listener
};

#endif // __HELLOWORLD_SCENE_H__
</pre><pre name="code" class="cpp">#include "HelloWorldScene.h"


USING_NS_CC;
USING_NS_CC_EXT;
using namespace std;


#define TILE_SIZE 32
#define PT_RATIO 32  // 这个数一般定义为: 32.0,在box 世界中 是以 米 为单位的,这里是将坐标兑换为box世界中的米,即除以 PTM_RATIO


//--------------------------------------------


HelloWorld::HelloWorld()
{


}


HelloWorld::~HelloWorld()
{
  if(world)
    delete world;
}


CCScene* HelloWorld::scene()
{
  // 'scene' is an autorelease object
  CCScene *scene = CCScene::create();


  // 'layer' is an autorelease object
  HelloWorld *layer = HelloWorld::create();


  // add layer as a child to scene
  scene->addChild(layer);


  // return the scene
  return scene;
}


enum 
{
    kTagTileMap = 1,
};


CCLabelTTF* pLabel;
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
  //
  // 1. super init first
  if ( !CCLayer::init() )
  {
    return false;
  }


  pLabel = CCLabelTTF::create("Collsion", "Arial", 24);
  CCSize size = CCDirector::sharedDirector()->getWinSize();


  // position the label on the center of the screen
  pLabel->setPosition( ccp(size.width / 2, size.height - 50) );


  // add the label as a child to this layer
  this->addChild(pLabel, 1, 0);


  // create physic world
  b2Vec2 gravity(0,0);
  world = new b2World(gravity);
  world->SetAllowSleeping(false);


  contactListener = new MyContactListener();
  world->SetContactListener(contactListener);


  spawnCar();
    
  schedule(schedule_selector(HelloWorld::tick));
  schedule(schedule_selector(HelloWorld::secondUpdate), 1.f);
  setTouchEnabled(true);
  return true;
}




void HelloWorld::tick(float dt)
{
  if (world)
    world->Step(dt, 10, 10);


  // 基于cocos2d的精灵位置来更新box2d的body位置
  for(b2Body* b = world->GetBodyList(); b; b = b->GetNext())
  {
    if (b->GetUserData() != NULL)
    {
      CCSprite* sprite = (CCSprite*)b->GetUserData();
      if (sprite)
      {
        b2Vec2 pt = b2Vec2((float)(sprite->getPosition().x / PT_RATIO), (float)(sprite->getPosition().y / PT_RATIO));
        float angle = (CCFloat)CC_DEGREES_TO_RADIANS(sprite->getRotation());
        b->SetTransform(pt, angle);
      }
    }
  }


  std::list<b2Body*> toDestroy_list;


  for( std::list<MyContact>::iterator it = contactListener->contact_list.begin(); 
                              it != contactListener->contact_list.end();
                              ++it)
  {
    MyContact& contact = *it;


    b2Body* bodyA = contact.fixtureA->GetBody();
    b2Body* bodyB = contact.fixtureB->GetBody();


    CCSprite* sa = (CCSprite*)bodyA->GetUserData();
    CCSprite* sb = (CCSprite*)bodyB->GetUserData();
    if (sa && sb)
    {
      if (sa->getTag() == 1 && sb->getTag() == 2)
        toDestroy_list.push_back(bodyB);
      else if (sa->getTag() == 2 && sa->getTag() == 1)
        toDestroy_list.push_back(bodyA);
    }
  }
  
  // Destroy contact item.
  std::list<b2Body*>::iterator it = toDestroy_list.begin();
  while(it != toDestroy_list.end())
  {
    if ((*it)->GetUserData() != NULL)
    {
      CCSprite* sprite = (CCSprite*)((*it)->GetUserData());
      if (sprite)
      {
        removeChild(sprite, true);
      }
      world->DestroyBody(*it);
    }


    ++it;
  }


  toDestroy_list.clear();
  
}


void HelloWorld::spawnCar()
{
  CCSprite* car = CCSprite::spriteWithFile("images/car.png");
  car->setPosition(ccp(100,100));


  car->runAction(CCRepeatForever::actionWithAction((CCActionInterval*)CCSequence::actions(
    CCMoveTo::actionWithDuration(1.0f, ccp(300,100)),
    CCMoveTo::actionWithDuration(1.0f, ccp(200,200)),
    CCMoveTo::actionWithDuration(1.0f, ccp(100,100)),
    NULL
    )));


  addBoxBodyForSprite(car);
  this->addChild(car, 1, 1);
}


void HelloWorld::spawnCat()
{
  CCSize winSize = CCDirector::sharedDirector()->getWinSize();
  CCSprite* cat = CCSprite::spriteWithFile("images/cat.png");


  float minY = cat->getContentSize().height/2;
  float maxY = winSize.height - cat->getContentSize().height/2;
  float y = minY + rand() % (int)(maxY - minY);


  float startX = winSize.width + cat->getContentSize().width/2;
  float endX = -cat->getContentSize().width/2;


  CCPoint startPos = ccp(startX, y);
  CCPoint endPos = ccp(endX, y);


  cat->setPosition(startPos);


  cat->runAction(CCSequence::actions(CCMoveTo::actionWithDuration(10.f, endPos), 
    CCCallFuncN::actionWithTarget(this, callfuncN_selector(HelloWorld::spriteDone)), NULL));




  addBoxBodyForSprite(cat);
  addChild(cat, 1, 2);
}


void HelloWorld::addBoxBodyForSprite(cocos2d::CCSprite* sprite)
{
  //PTM_RATIO  ,这个数一般定义为: 32.0,在box 世界中 是以 米 为单位的,这里是将坐标兑换为box世界中的米,即除以 PTM_RATIO


  // Create physic body for cat
  b2PolygonShape polygon;
  polygon.SetAsBox((float)sprite->getContentSize().width/PT_RATIO/2, (float)sprite->getContentSize().height/PT_RATIO/2);


  b2FixtureDef spriteShapeDef;
  spriteShapeDef.shape = &polygon;
  spriteShapeDef.density = 10.f;
  spriteShapeDef.isSensor = true;   // 对象之间有碰撞检测但是又不想让它们有碰撞反应


  b2BodyDef bd;
  bd.type = b2_dynamicBody;
  bd.position = b2Vec2((float)(sprite->getPosition().x / PT_RATIO),
    (float)(sprite->getPosition().y /PT_RATIO));
  bd.userData = sprite;


  b2Body* spriteBody = world->CreateBody(&bd);
  spriteBody->CreateFixture(&spriteShapeDef);
}






void HelloWorld::spriteDone(CCNode* sender)
{
  // sprites被销毁的时候,我们需要销毁Box2d的body
  CCSprite* sprite = dynamic_cast<CCSprite*>(sender);
  if (sprite)
  {
    b2Body* spriteBody = NULL;
    for(b2Body* b = world->GetBodyList(); b; b=b->GetNext())
    {
      if (b->GetUserData() != NULL)
      {
        CCSprite* curSprite = (CCSprite*)b->GetUserData();
        if (curSprite == sprite)
        {
          spriteBody = b;


          removeChild(sprite, true);
          world->DestroyBody(spriteBody);
          break;
        }
      }


      //if (spriteBody)
      //{
      //  world->DestroyBody(spriteBody);
      //}


      // removeChild(sprite, true);
    }
  }
}


void HelloWorld::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)
{
  CCSetIterator iter = pTouches->begin();
  for (; iter != pTouches->end(); iter++)
  {
    CCTouch* pTouch = (CCTouch*)(*iter);
    CCPoint pos = pTouch->locationInView();
    pos = CCDirector::sharedDirector()->convertToGL(pos);


  }
}


void HelloWorld::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent)
{
  CCSetIterator iter = pTouches->begin();
  for (; iter != pTouches->end(); iter++)
  {
    CCTouch* pTouch = (CCTouch*)(*iter);
    CCPoint pos = pTouch->locationInView();


    CCPoint touchLocation = pTouch->locationInView();    
    CCPoint prevLocation = pTouch->previousLocationInView();    
    
/*    touchLocation = CCDirector::sharedDirector()->convertToGL( touchLocation );
    prevLocation = CCDirector::sharedDirector()->convertToGL( prevLocation );
    
    CCPoint diff = ccpSub(touchLocation, prevLocation);
    
    CCNode *node = getChildByTag(kTagTileMap);
    CCPoint currentPos = node->getPosition();


    node->setPosition( ccpAdd(currentPos, diff) )*/;
  }
}


void HelloWorld::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{
  CCSetIterator iter = pTouches->begin();
  for (; iter != pTouches->end(); iter++)
  {
    CCTouch* pTouch = (CCTouch*)(*iter);
  }
}


void HelloWorld::ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent)
{
  ccTouchesEnded(pTouches, pEvent);
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值