您的位置:首页 > 移动开发 > IOS开发

使用b2MouseJoint实现鼠标拖拽刚体的效果

2017-01-03 21:09 387 查看

要在Box2d中实现鼠标拖拽效果(当然在移动设备上就不是鼠标拖拽而是手指拖拽了),可以使用Box2d中定义的b2MouseJoint来制作。大体思路是,首先在ccTouchBegan事件中获取鼠标(以下不再区分鼠标或是手指)所在位置的刚体(如果有的话),接着在ccTouchMoved事件中通过更新b2MouseJoint的target的位置(更新为鼠标的当前位置),最后在ccTouchEnded事件中清理掉b2MouseJoint让刚体受力自由运动。
首先我们来完成获取鼠标所在位置的刚体的代码。
以cocos2d iOS with Box2d为模板创建Box2d工程(本文使用的是Box2d2.3.1版本),接着我们去掉HelloWorldLayer的addNewSpriteAtPosition方法中为盒子对象添加的纹理贴图部分(这样我们看到的就是原始的刚体骨架了,个人喜好哈哈),接着我们在HelloWorldLayer的init方法中把menu相关的代码都给注释掉,让我们的界面看着更简洁一些,然后使用循环,调用addNewSpriteAtPosition方法向场景中添加若干个盒子刚体来用于测试:
for (int i =0; i < 20; i++) {
   [self addNewSpriteAtPosition:ccp(s.width/2,s.height/2)];
}
添加完成后试运行一下:



这里我们添加了20个刚体。
接着把HelloWorldLayer的ccTouchesEnded方法全部注释掉。
接着我们让HelloWorldLayer继承ccTouchOneByOneDelegate协议,在HelloWorldLayer中重载两个方法用于注册和反注册touch事件分发:
-(void)onEnterTransitionDidFinish {
   [[[CCDirector sharedDirector]touchDispatcher] addTargetedDelegate:self priority:1 swallowsTouches:true];
}
 
-(void) onExit{
   [[[CCDirector sharedDirector]touchDispatcher] removeDelegate:self];
}
 
下面我们来说一下如何获取鼠标位置的刚体。
首先,鼠标的位置可以在touch事件中使用传入的参数touch来获取:
CGPointtouchLocation = [[CCDirector sharedDirector] convertToGL:[touchlocationInView:[touch view]]];
接着我们通过Box2d的AABB Query来获取某个区域内的所有fixture。
在工程中添加一个类MyQueryCallback,继承自b2QueryCallback:
类声明:
#import"Box2D.h"
 
classMyQueryCallback : public b2QueryCallback {
public:
   b2Body* body;
   MyQueryCallback();
   bool ReportFixture(b2Fixture* fixture);
};
类的方法实现:
#import"MyQueryCallback.h"
 
MyQueryCallback::MyQueryCallback(){
   body = nil;
}
 
boolMyQueryCallback::ReportFixture(b2Fixture* fixture) {
   body = fixture->GetBody();
   return false;
}
在方法实现中我们实现了ReportFixture方法,该方法作为AABBQuery的回调方法被调用。类中我们定义了一个b2Body刚体用来保存查询到的刚体对象。返回false表示停止继续查询,返回true则表示继续查询。
接着我们在HelloWorldLayer实现ccTouchBegan方法:
-(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {

 //获取鼠标位置
   CGPoint touchLocation = [[CCDirectorsharedDirector] convertToGL:[touch locationInView:[touch view]]];
   MyQueryCallback callback;
   b2AABB aabb;

float margin = 0.00000000001f;

//定义一个AABB线框
   aabb.lowerBound.Set((touchLocation.x -margin) / PTM_RATIO, (touchLocation.y + margin) / PTM_RATIO);   //线框左上角
   aabb.upperBound.Set((touchLocation.x +margin) / PTM_RATIO, (touchLocation.y - margin) / PTM_RATIO);   //线框右下角
   world->QueryAABB(&callback,aabb);   //查询线框内的物体
   if (callback.body != nil) {
       //创建b2MouseJoint关节
   }
   
   return true;
}
在上面的代码中,首先以鼠标点击的位置为中心创建一个很小的矩形区域(即AABB),再定义我们自己的MyQueryCallback实例,调用QueryAABB方法来查询在AABB中的刚体,将结果反馈到MyQueryCallback中(通过ReportFixture方法)。
判断如果callback的body成员不为空(nil),说明鼠标点击的位置有刚体存在,然后就可以利用得到的刚体来创建b2MouseJoint了,下面是创建的具体代码:
if (mouseJoint!= nil) {
   world->DestroyJoint(mouseJoint);
   mouseJoint = nil;
}
body =callback.body;
b2MouseJointDefmouseJointDef;
b2BodyDefbodyDef;
b2Body*emptyBody = world->CreateBody(&bodyDef);   //创建一个空的刚体,这个刚体在b2MouseJoint中实际没有用到,只是为了满足创建Joint的一致性而使用,注意 不能是nil
mouseJointDef.bodyA= emptyBody;
mouseJointDef.bodyB= body;   //bodyB就是鼠标所在位置的刚体
mouseJointDef.target.Set(touchLocation.x/ PTM_RATIO, touchLocation.y / PTM_RATIO);   //设置Target,刚体就会向Target“飞去”
mouseJointDef.maxForce= 200;   //设置最大受力,受力越大,物体向Target飞过去的加速度就越快
mouseJoint =world->CreateJoint(&mouseJointDef);
注:需要在HelloWorldLayer中添加两个成员变量:
b2Body* body;
b2Joint*mouseJoint;
上面的代码中首先判断前一个mouseJoint是否已经清理掉了(因为这个成员是复用的,所以如果没有清理掉容易出问题)。接着通过定义b2MouseJointDef中的各项参数来创建关节(代码已经做过注释,不多赘述)。
完成后,还需要实现ccTouchMoved和ccTouchEnded两个方法:
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
   CGPoint touchLocation = [[CCDirectorsharedDirector] convertToGL:[touch locationInView:[touch view]]];
   if (body != nil) {
       b2Vec2 target(touchLocation.x /PTM_RATIO, touchLocation.y / PTM_RATIO);
       ((b2MouseJoint*)mouseJoint)->SetTarget(target);
   }
}
 
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
   if (mouseJoint != nil) {
       world->DestroyJoint(mouseJoint);
       mouseJoint = nil;
       body = nil;
   }
}
ccTouchMoved方法在鼠标移动的时候要实时更新MouseJoint的Target的位置,以便形成鼠标“拖拽”的效果。ccTouchEnded方法清理掉MouseJoint,这样物体在鼠标松开后便会回归到自然受力的状态(重力还有其他物体的力)。
好了,大功告成,测试一下效果:



哈哈,现在我们可以把盒子扔的满天飞了~~
 
好了,例子就到这里,如果有问题欢迎留言。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  IOS box2d 鼠标 拖拽 关节