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

原创 2017年01月03日 21:09:12


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

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


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

 

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


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

学习 Box2D 个人笔记(四)b2MouseJoint

这个玩意是干啥的呢 ,这个玩意是能拖动刚体的东西。也就是说 触摸的时候可以随着手指运动。首先 ,我们要有一个刚体 ,这个相信很多同学都会添加。 b2Body * spriteBody; ...

cocos2d-x box2d物理引擎深入研究 第一篇之鼠标关节详解(b2MouseJoint)

在testbed例子中,使用鼠标关节操作刚体,他尝试在刚体上驱动一个点,拖向当前的鼠标位置,在旋转方面没有任何限制. 鼠标关节定义有目标点(target point),最大力矩(maxinum ...

鼠标拖拽效果原理及完整代码实现

鼠标拖拽事件完整代码实现

PyQt5学习记录(7)---监听鼠标拖拽事件实现Mac上百度云盘拖拽效果

背景在Mac版的百度云盘上有这样一个效果,拖拽一个文件过来,将会显示边框蓝色非常醒目的提醒了操作者。本文介绍用PyQt5监听鼠标的拖拽事件,实现一个类似的效果,当拖拽时动态的改变整个界面边框颜色.下面...

使用js中常用的鼠标事件实现一个拖拽的例子

一、js中常用的几个必备鼠标事件 onclick: 元素上发生鼠标点击时触发. ondblclick: 元素上发生鼠标双击时触发. onmousedown: 当元素上按下鼠标按钮时触发. onmous...

鼠标拖拽效果

这次要做的是鼠标拖动效果,说白了就是鼠标可以拖动网页上的一些组件(div),最普遍的就是在网页进行登录验证的时候,当点击登陆的时候会弹出一个登陆框,这个登陆框是出于屏幕中间的,浮于网页所有元素之上,可...

Cocos2d实现类似Clash of clans的缩放拖拽效果

最近开始跳入做游戏的坑了,而且想做一款独立游戏,虽然随时有烂尾的危险,但无妨一试~敬请期待~ 目前正在准备游戏的原型,由于需要设计像COC的缩放场景,作为cocos2d的菜鸟兼ios开发新手,实在s...

鼠标拖拽层的效果

  • 2011-11-21 08:53
  • 740B
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)