cocos2d学习笔记(八)物理引擎box2d之二

今天我们来看看如何通过拖拽移动一个物体


拖移物体需要用到box2d中的b2MouseJoint

首先我们在touchbegan方法中为我们点击到的物体创建b2MouseJoint对象,那么问题来了,我们如何获取点击到的物体呢?

box2d为我们提供了相关方法,即AABB(axis-aligned bounding box    ),原理为:首先,我们点击位置的四边加上了1-point的边,这样我们点击的位置变成了一个小方块;之后,以某个形状的物体做个长方形,看看我们点击的位置是否在这个长方形里面。如图:


如果在,那么调用callback对象,这个callback对象是我们自己写的,可以通过TestPoint看看点击的位置是否的确在AABB找出的物体上,如果在,那么我们就获取到了点击的物体。上图可以发现其实我们并没有点到那个黑色的物体上,所以TestPoint会返回false。如果同时点到了多个物体,只返回第一个被发现的。


之后是touch began代码,我们可以看到b2MouseJoint如何被创建的:

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    for( UITouch *touch in touches ) {
        CGPoint location = [touch locationInView:touch.view];
        location = [[CCDirector sharedDirector] convertToGL:location];
        location = [self convertToNodeSpace:location];
        b2Vec2 b2Location = b2Vec2(location.x / PTM_RATIO, location.y / PTM_RATIO);
        
        b2AABB aabb;
        b2Vec2 delta = b2Vec2(1.0 / PTM_RATIO, 1.0 / PTM_RATIO);
        aabb.upperBound = b2Location + delta;
        aabb.lowerBound = b2Location - delta;
        
        SimpleQueryCallback callback(b2Location);
        world->QueryAABB(&callback, aabb);
        
        if (callback.fixtureFound) {
            b2Body *body = callback.fixtureFound->GetBody();
            CCSprite *sprite = (CCSprite *)body->GetUserData();
            if (sprite == nil) {
                return;
            }
            b2MouseJointDef mouseJointDef;
            mouseJointDef.bodyA = groundBody;
            mouseJointDef.bodyB = body;
            mouseJointDef.target = b2Location;
            mouseJointDef.maxForce = 1000 * body->GetMass();
            mouseJointDef.collideConnected = true;
            
            mouseJoint = (b2MouseJoint *) world->CreateJoint(&mouseJointDef);
            body->SetAwake(true);
        } else {
            [self addNewSpriteWithCoords: location];
        }
    }
}
其中bodyA一般会指定固定的body,bodyB指定你想移动的body,target为你要移动到哪里,maxForce越大,拖动速度越快,collideConnected为true时bodyA和bodyB会相撞。

SimpleQueryCallback是我们自己写的一个类:

class SimpleQueryCallback : public b2QueryCallback
{
public:
    b2Vec2 pointToTest;
    b2Fixture * fixtureFound;
    
    SimpleQueryCallback(const b2Vec2& point) {
        pointToTest = point;
        fixtureFound = NULL;
    }
    
    bool ReportFixture(b2Fixture* fixture) {
        b2Body* body = fixture->GetBody();
        if (body->GetType() == b2_dynamicBody) {
            if (fixture->TestPoint(pointToTest)) {
                fixtureFound = fixture;
                return false;
            }
        }        
        return true;
    }        
};

然后是move和touch ended的代码,move中setTarget即会使物体移到新位置,别忘了在touch ended中销毁这个mouseJoint

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    for( UITouch *touch in touches ) {
        CGPoint location = [touch locationInView:touch.view];
        location = [[CCDirector sharedDirector] convertToGL:location];
        location = [self convertToNodeSpace:location];
        b2Vec2 b2Location = b2Vec2(location.x / PTM_RATIO, location.y / PTM_RATIO);
        
        if (mouseJoint) {
            mouseJoint->SetTarget(b2Location);
        }
    }
}

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	//Add a new body/atlas sprite at the touched location
	for( UITouch *touch in touches ) {
		CGPoint location = [touch locationInView: [touch view]];
		
		location = [[CCDirector sharedDirector] convertToGL: location];
		
//		[self addNewSpriteWithCoords: location];
        if (mouseJoint) {
            world->DestroyJoint(mouseJoint);
            mouseJoint = NULL;
        }
	}
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值