您的位置:首页 > 移动开发 > Cocos引擎

cocos2d-x 菜鸟学习笔记十四(简单的碰撞检测 进阶篇)

2013-06-05 11:44 549 查看
上一篇记录了chipmunk的使用流程,其实还算不上是碰撞检测,但在游戏中需要利用这些碰撞事件来执行对应的动作,这就涉及到另一部分的内容了,即怎样在发生碰撞事件的时候调用对应的工作代码。

首先是为碰撞事件设定回调函数:

在chipmunk中有两种设定碰撞回调函数的方法,一种是cpSpaceSetDefaultCollisionHandler,另一种是cpSpaceAddCollisionHandler。

cpSpaceSetDefaultCollisionHandler是为物理空间设定默认的碰撞回调函数,它的设置是针对全局的,也就是物理空间里任何对象的碰撞都会执行设定的回调函数:

void cpSpaceSetDefaultCollisionHandler(
cpSpace *space,
cpCollisionBeginFunc begin,
cpCollisionPreSolveFunc preSolve,
cpCollisionPostSolveFunc postSolve,
cpCollisionSeparateFunc separate,
void *data
);


cpSpaceAddCollisionHandler用来设定自定义的碰撞回调规则,比上面多出了两个参数,用来指定物理空间中哪类对象碰撞时执行回调函数:

void cpSpaceAddCollisionHandler(
cpSpace *space,
cpCollisionType a, cpCollisionType b,
cpCollisionBeginFunc begin,
cpCollisionPreSolveFunc preSolve,
cpCollisionPostSolveFunc postSolve,
cpCollisionSeparateFunc separate,
void *data
);


由于对其中四个参数不太了解,所以实验了下,这里就顺便把用法一起写出来。碰撞回调允许在四个碰撞状态下执行,每种碰撞状态的回调使用方式也不一样:

//碰撞开始时的回调
static int beginCollision(cpArbiter *arb, cpSpace *space, void *data);
//单次碰撞准备结束时的回调
static int preSolveCollision(cpArbiter *arb, cpSpace *space, void *data);
//单次碰撞结束时的回调
static void postSolveCollision(cpArbiter *arb, cpSpace *space, void *data);
//碰撞对象分离后的回调
static void seperateCollision(cpArbiter *arb, cpSpace *space, void *data);


回调代码:

int HelloWorld::beginCollision(cpArbiter *arb, cpSpace *space, void *data){
CCLog("begin collision");
//返回值为false时,碰撞对象会只在初次碰撞时执行回调函数,两个碰撞对象会重叠在一起
return false;
}

int HelloWorld::preSolveCollision(cpArbiter *arb, cpSpace *space, void *data)
{
CCLog("preSolve collision");
//当返回值为false时将会一直调用此回调函数,直到碰撞对象分离,两个碰撞对象会重叠在一起
return true;
}
void HelloWorld::postSolveCollision(cpArbiter *arb, cpSpace *space, void *data)
{
CCLog("PostSolve collision");
}
void HelloWorld::seperateCollision(cpArbiter *arb, cpSpace *space, void *data){
CCLog("Seperate collision");
}


指定两类对象在碰撞时执行设定的回调函数:

shape->collision_type=1;    //为shape设定碰撞类型标识参数
cpSpaceAddShape(m_pSpace, shape);
cpSpaceAddCollisionHandler(m_pSpace,1,1,beginCollision,preSolveCollision,postSolveCollision,seperateCollision,NULL);


当发生碰撞时,我们有时会想要取得碰撞对象的信息,比如判断是哪个对象被碰撞、碰撞对象所在的位置……这就需要在添加精灵时加一句:

//这里用于将精灵的数据装载进shape中的data里待后面需要时调用对应数据
shape->data=sprite


前面说了在碰撞时可以有四个回调函数,在这四个回调函数里都可以获取对应的物理对象及数据如:

int HelloWorld::beginCollision(cpArbiter *arb, cpSpace *space, void *data){
//获取碰撞的shape,a代表用cpSpaceAddCollisionHandler添加碰撞回调时的碰撞对象类型a,b亦然
CP_ARBITER_GET_SHAPES(arb, a, b);
CCLog("begin collision p_x:%1.1f p_y:%1.1f",a->body->p.x,a->body->p.y);
//设置物理空间在结束当前动作时的回调函数,用于安全释放对象,此调用只会在完成当前动作后调用一次
cpSpaceAddPostStepCallback(space,(cpPostStepFunc)postStepRemove,a,NULL);
//返回值为false时,碰撞对象会只在初次碰撞时执行回调函数,两个碰撞对象会重叠在一起
return true;
}


在上面,我在碰撞开始时我通过CP_ARBITER_GET_SHAPES获取了碰撞对象类型为1(即碰撞形状代号为a)的刚体的坐标数据并输出到日志,并调用了一个用于销毁碰撞对象a的回调函数postStepRemove,看看里面的对应代码:

void HelloWorld::postStepRemove(cpSpace *space, cpShape *shape, void *unused){
//CCLog("postStep p_x:%1.f p_y:%1.f",shape->body->p.x,shape->body->p.y);
CCPhysicsSprite *sprite = (CCPhysicsSprite*)shape->data;

//CCLog("%1d",sprite->getTag());

//释放碰撞的对象,这里释放时要注意顺序
//先释放形状
cpSpaceRemoveShape(space, shape);
cpShapeFree(shape);
//释放刚体
cpSpaceRemoveBody(space, sprite->getCPBody());
cpBodyFree(sprite->getCPBody());
//移除精灵
sprite->removeFromParentAndCleanup(true);

}


通过上面添加的代码,就可以实现碰撞事件产生时获取需要的信息,并且在不需要时释放掉,自己改装一下就可以做出一个子弹碰撞怪物时的kill事件。

碰撞检测进阶篇源码:http://download.csdn.net/detail/cyistudio/5522053
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: