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

WaJ*_*yaz 4 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);
Run Code Online (Sandbox Code Playgroud)

我在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);      
}
Run Code Online (Sandbox Code Playgroud)

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

Luk*_*man 5

让我进一步阐述duffymo的答案.

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

int32 velocityIterations = 8;
int32 positionIterations = 1;

world->Step(dt, velocityIterations, positionIterations);
Run Code Online (Sandbox Code Playgroud)

两个int32变量告诉box2D它应该做多少次迭代(即通过)来应用力,检测碰撞等.根据box2D手册,增加这些值会以性能为代价提高模拟的准确性,反之亦然.值.所以我建议你调整这些值,特别是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
}
Run Code Online (Sandbox Code Playgroud)