在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来驱动物理的,物理物体本身不做物理模拟,只做碰撞检测,适合用来做子弹射击物体。
- 本文固定链接: http://www.wy182000.com/2013/12/09/cocos2d-x-chipmunk用来做碰撞检测/
- 转载请注明: wy182000 于 Studio 发表