4

我知道 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);      
}

就是简单地计算触球点到球的距离,根据距离找到对球施加的力量,然后将球向触球方向移动。这个球与任何其他进入它的球相撞。

4

2 回答 2

5

让我进一步详细说明 duffymo 的回答。

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

int32 velocityIterations = 8;
int32 positionIterations = 1;

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

这两个 int32 变量告诉 box2D 应该执行多少次迭代(即通过)来施加力、检测碰撞等。根据box2D 手册,增加这些值会以性能为代价提高模拟的准确性,反之亦然以减少这些价值观。所以我建议你调整这些值,尤其是 positionIterations,直到你对结果满意为止。

编辑:

Here is another suggestion. Remember again that the tick method is being called at the same rate as the fps, which is at most 60 per second? That means the b2World::Step function is doing discrete simulation at 1/60 second intervals, so a fast moving body manage to pass through another body if it takes less than that amount of time. So to solve this, you need to increase the frequency of the discrete simulation, let's say to 180 steps per second. But the question is how? Cocos2D-iPhone calls the tick method for every frame, and increasing the framerate (if it's even possible) will reduce the performance and waste all the processing power.

Here's how you can do it without changing the framerate, by calling the b2World::Step function a couple of times within the same tick:

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
}
于 2011-03-22T16:40:44.560 回答
0

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

于 2011-03-19T13:28:21.693 回答