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

103 篇文章 0 订阅
53 篇文章 0 订阅


要在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,这样物体在鼠标松开后便会回归到自然受力的状态(重力还有其他物体的力)。

好了,大功告成,测试一下效果:


哈哈,现在我们可以把盒子扔的满天飞了~~

 

好了,例子就到这里,如果有问题欢迎留言。


  • 84
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值