注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

风的驿站

一徐清风,半指烛光,觥筹已净,只余茶香。残卷一章,妙趣非常,忽闻帘响,愿闻其详?

 
 
 

日志

 
 
关于我

喜欢写生 编程 音乐 设计 喜欢把自己的想法变成实实在在的东西 喜欢安静的做一些事情 CSDN博客:http://blog.csdn.net/qwertyupoiuytr

网易考拉推荐

【原创】使用b2MouseJoint实现鼠标拖拽刚体的效果  

2014-08-19 15:04:36|  分类: Box2D |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

要在Box2d中实现鼠标拖拽效果(当然在移动设备上就不是鼠标拖拽而是手指拖拽了),可以使用Box2d中定义的b2MouseJoint来制作。大体思路是,首先在ccTouchBegan事件中获取鼠标(以下不再区分鼠标或是手指)所在位置的刚体(如果有的话),接着在ccTouchMoved事件中通过更新b2MouseJointtarget的位置(更新为鼠标的当前位置),最后在ccTouchEnded事件中清理掉b2MouseJoint让刚体受力自由运动。

首先我们来完成获取鼠标所在位置的刚体的代码。

cocos2d iOS with Box2d为模板创建Box2d工程(本文使用的是Box2d 2.3.1版本),接着我们去掉HelloWorldLayeraddNewSpriteAtPosition方法中为盒子对象添加的纹理贴图部分(这样我们看到的就是原始的刚体骨架了,个人喜好哈哈),接着我们在HelloWorldLayerinit方法中把menu相关的代码都给注释掉,让我们的界面看着更简洁一些,然后使用循环,调用addNewSpriteAtPosition方法向场景中添加若干个盒子刚体来用于测试:

for (int i = 0; i < 20; i++) {

    [self addNewSpriteAtPosition:ccp(s.width/2, s.height/2)];

}

添加完成后试运行一下:

【原创】使用b2MouseJoint实现鼠标拖拽刚体的效果 - 远行的风 - 风的驿站

这里我们添加了20个刚体。

接着把HelloWorldLayerccTouchesEnded方法全部注释掉。

接着我们让HelloWorldLayer继承ccTouchOneByOneDelegate协议,在HelloWorldLayer中重载两个方法用于注册和反注册touch事件分发:

-(void) onEnterTransitionDidFinish {

    [[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:1 swallowsTouches:true];

}

 

-(void) onExit {

    [[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];

}

 

下面我们来说一下如何获取鼠标位置的刚体。

首先,鼠标的位置可以在touch事件中使用传入的参数touch来获取:

CGPoint touchLocation = [[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]];

接着我们通过Box2dAABB Query来获取某个区域内的所有fixture

在工程中添加一个类MyQueryCallback,继承自b2QueryCallback

类声明:

#import "Box2D.h"

 

class MyQueryCallback : public b2QueryCallback {

public:

    b2Body* body;

    MyQueryCallback();

    bool ReportFixture(b2Fixture* fixture);

};

类的方法实现:

#import "MyQueryCallback.h"

 

MyQueryCallback::MyQueryCallback() {

    body = nil;

}

 

bool MyQueryCallback::ReportFixture(b2Fixture* fixture) {

    body = fixture->GetBody();

    return false;

}

在方法实现中我们实现了ReportFixture方法,该方法作为AABB Query的回调方法被调用。类中我们定义了一个b2Body刚体用来保存查询到的刚体对象。返回false表示停止继续查询,返回true则表示继续查询。

接着我们在HelloWorldLayer实现ccTouchBegan方法:

-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {

       //获取鼠标位置

    CGPoint touchLocation = [[CCDirector sharedDirector] 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方法)。

判断如果callbackbody成员不为空(nil),说明鼠标点击的位置有刚体存在,然后就可以利用得到的刚体来创建b2MouseJoint了,下面是创建的具体代码:

if (mouseJoint != nil) {

    world->DestroyJoint(mouseJoint);

    mouseJoint = nil;

}

body = callback.body;

b2MouseJointDef mouseJointDef;

b2BodyDef bodyDef;

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中的各项参数来创建关节(代码已经做过注释,不多赘述)。

完成后,还需要实现ccTouchMovedccTouchEnded两个方法:

-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {

    CGPoint touchLocation = [[CCDirector sharedDirector] 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方法在鼠标移动的时候要实时更新MouseJointTarget的位置,以便形成鼠标“拖拽”的效果。ccTouchEnded方法清理掉MouseJoint,这样物体在鼠标松开后便会回归到自然受力的状态(重力还有其他物体的力)。

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

【原创】使用b2MouseJoint实现鼠标拖拽刚体的效果 - 远行的风 - 风的驿站

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

 

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

  评论这张
 
阅读(89)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017