首页 > Personal > cocos2d-x > cocos2d-x: chipmunk用来做碰撞检测
2013
12-09

cocos2d-x: chipmunk用来做碰撞检测

在cocos2d-x提供了两个物理引擎,一个是Box2d,一个是chipmunk。两个引擎最明显的区别是Box2d是c++接口的,chipmunk是c接口的。之前2d物理引擎一直都是使用Box2d,但是cocos2d-x的javascript版本提供的是chipmunk接口,所以为了以后可以使用js脚本编写游戏,所以选择chipmunk来用。

在scene的头文件需要添加
#include “cocos-ext.h”
#include “chipmunk.h”

添加变量
cpSpace* cp_space_;
cocos2d::extension::CCPhysicsDebugNode* debug_layer_; // for debug

在scene的初始化时配置chipmunk的初始化,
cp_space_ = cpSpaceNew();
cpSpaceSetGravity(cp_space_, cpv(0, 0)); // gravity set to 0
debug_layer_ = extension::CCPhysicsDebugNode::create(cp_space_); // for debug
this->addChild(debug_layer_, 100); // debug z order 100

在scene的update里调用
cpSpaceStep(cp_space_, dt);
来更新物理世界。

接下来在需要的创建怪物的地方创建动态物体
cpVect verts[] = {
  cpv(-14, –20);
  cpv(-14, 20),
  cpv(14, 20),
  cpv(14, -20),
};
cpBody* body = cpBodyNew(1.f, cpMomentForPoly(1.f, 4, verts, cpvzero));
第一个参数是物体的质量,第二个参数是物体的惯性,可以用上面的函数cpMomentForPoly计算出来,还可以使用INFINITY。

设置物体初始位置
cpBodySetPos(body, cpv(target->getPosition().x, target->getPosition().y));

将物体加入物理世界
cpSpaceAddBody(cp_space_, body);

然后创建物体的物理形状shape
cpShape* shape = cpPolyShapeNew(body, 4, verts, cpvzero);

修改shape的反弹参数,和惯性摩擦力
cpShapeSetElasticity(shape, 1.f);
cpShapeSetFriction(shape, 1.f);

设置collision type
cpShapeSetCollisionType(shape, 1);

添加需要绑定的script到shape上
cShapeSetUserData(shape, target);

关联shape到script上
target->setUserData(shape);

将shape加入物理世界
cpSpaceAddShape(cp_space_, shape);

在创建子弹的地方用同上的方法创建动态物体,修改大小,将collision type设为2。

在物理初始化的地方注册collision handler的回调函数,将scene当参数this传入
cpSpaceAddCollisionHandler(cp_space_, 1, 2, collistion_begin, NULL, NULL, NULL, this);

如果不需要哪些类型碰撞也需要注册collision handler的回调,如
cpSpaceAddCollisionHandler(cp_space_, 1, 1, collistion_cancel, NULL, NULL, NULL, this);
cpSpaceAddCollisionHandler(cp_space_, 2, 2, collistion_cancel, NULL, NULL, NULL, this);
collision_cancel直接返回0即可。

添加collision begin的函数,来处理碰撞开始
static int collistion_begin(cpArbiter* ar, cpSpace* space, void* scene) {
  // get the collision shapes
  CP_ARBITER_GET_SHAPES(ar, a, b);
  cpSpaceAddPostStepCallback(space, (cpPostStepFunc)post_step_remove, a, scene);
  cpSpaceAddPostStepCallback(space, (cpPostStepFunc)post_step_remove, b, scene);
  return 0;
}

添加两个碰撞物体的post step 回调,以便安全的删除他们
// post step remove
static void post_step_remove(cpSpace* space, cpShape* shape, void* scene) {
  if (shape->data) {
    ((HelloWorld*)scene)->release_sprite(shape->data);
  }
}

定义函数release sprite 来删除sprite和上面的shape
void HelloWorld::release_sprite(void* s) {
  CCSprite* sprite = static_cast<CCSprite*>(s);
  this->removeChild(sprite);
  void* data = sprite->getUserData();
  if (data) {
    cpShape* shape = static_cast<cpShape*>(data);
    cpBody* body = shape->body;
    cpSpaceRemoveShape(cp_space_, shape);
    cpShapeFree(shape);
    cpSpaceRemoveBody(cp_space_, body);
    cpBodyFree(body);
  }
  switch (sprite->getTag()) {
  case 1:
    targets_->fastRemoveObject(sprite);
    break;
  case 2:
    projectiles_->fastRemoveObject(sprite);
    break;
  }
}

在update函数中根据sprite的位置更新物理body的位置
CCObject* it = NULL;
CCARRAY_FOREACH(targets_, it) {
  CCSprite* sprite = static_cast<CCSprite*>(it);
  cpBody* body = ((cpShape*)sprite->getUserData())->body;
  cpBodySetPos(body, cpv(sprite->getPositionX(), sprite->getPositionY()));
}
CCARRAY_FOREACH(projectiles_, it) {
  CCSprite* sprite = static_cast<CCSprite*>(it);
  cpBody* body = ((cpShape*)sprite->getUserData())->body;
  cpBodySetPos(body, cpv(sprite->getPositionX(), sprite->getPositionY()));
}
cpSpaceStep(cp_space_, dt);
更新在物理的cpSpaceStep之前处理。

自己的例子是sprite来驱动物理的,物理物体本身不做物理模拟,只做碰撞检测,适合用来做子弹射击物体。

最后编辑:
作者:wy182000
这个作者貌似有点懒,什么都没有留下。

留下一个回复