Box2d中快速移动的物体有时会相互穿过

时间:2011-03-19 13:13:31

标签: cocos2d-iphone box2d-iphone

我知道Box2d世界中快速移动的物体会引起隧道效应并相互穿过。解决方案是将主体定义为子弹。我这样做但是身体有时仍然相互交叉,特别是如果遇到点不完全朝向中间并且身体在交叉时部分重叠。任何解决方案?

这就是我制作所有尸体的方式:

redBall = [CCSprite spriteWithFile:@"red-ball" rect:CGRectMake(0, 0, 34, 34)];
redBall.tag = 1;
[self addChild:redBall];
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set((winSize.width/2)/PTM_RATIO, redBall.position.y/PTM_RATIO);
ballBodyDef.userData = redBall;

ballBodyDef.bullet = true;
_ballBody = _world->CreateBody(&ballBodyDef);

// Create circle shape
b2CircleShape circle;
circle.m_radius = 17.0/PTM_RATIO;

// Create shape definition and add to body
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 0.2f;
ballShapeDef.friction = 0.0f;
ballShapeDef.restitution = 1.0f;
_ballFixture = _ballBody->CreateFixture(&ballShapeDef);

我在TouchesEnd中将此球移动为:

- (void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

    UITouch *myTouch = [touches anyObject];
    CGPoint location = [myTouch locationInView:[myTouch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];          

    CGPoint shootVector = ccpSub(location, striker.position);
    CGFloat shootAngle = ccpToAngle(shootVector);
    CGPoint normalizeShootVector = ccpNormalize(shootVector);

    float x1 = - cos(shootAngle);
    float y1 = - sin(shootAngle);

    int power = 0;
    float dist =ccpDistance(location, redBall.position);
    if (dist >= 200) 
        power = 20;
    else if (dist >= 100)
        power = 10;
    else if (dist >=75)
        power = 7;
    else if (dist >= 60)
        power = 4;
    else if (dist >= 50)
        power = 3;
    else if (dist >= 35)
        power = 2;
    else
        power = 1;

    b2Vec2 force = b2Vec2(x1*power, y1*power);
    _ballBody->ApplyLinearImpulse(force,ballBodyDef.position);      
}

它只是计算距离球的接触点的距离,根据距离找到施加在球上的力量并沿着触摸方向移动球。而且这个球碰到任何其他球。

2 个答案:

答案 0 :(得分:5)

让我进一步阐述duffymo的回答。

还记得CCLayer的tick方法包含以下代码吗?:

int32 velocityIterations = 8;
int32 positionIterations = 1;

world->Step(dt, velocityIterations, positionIterations);

两个int32变量告诉box2D它应该做多少迭代(即通过)来应用力,检测碰撞等。根据box2D manual,增加这些值可以提高模拟的准确性,但代价是性能,反之亦然,以减少这些值。因此,我建议您调整这些值,尤其是positionIterations,直到您对结果感到满意为止。

修改

这是另一个建议。再次记住,调用tick方法的速率与fps相同,每秒最多60次?这意味着b2World::Step函数以1/60秒的间隔进行离散模拟,因此如果花费的时间少于该时间,则快速移动的身体会设法通过另一个身体。所以要解决这个问题,你需要增加离散模拟的频率,比方说每秒180步。但问题是如何? Cocos2D-iPhone为每一帧调用tick方法,并且增加帧速率(如果它甚至可能)将降低性能并浪费所有处理能力。

通过在同一刻度内多次调用b2World::Step函数,您可以在不改变帧速率的情况下完成此操作:

int32 velocityIterations = 8;
int32 positionIterations = 1;
uint substeps = 3;
float32 subdt = dt / substeps;

for (uint i = 0; i < substeps; i++) {
    world->Step(subdt, velocityIterations, positionIterations);

    // do your physics-related stuff inside here but leave any sprites manipulation outside this loop
}

答案 1 :(得分:0)

您需要优化渗透检测:增加空间或时间或两者的灵敏度。