【问题标题】:Fast moving bodies in Box2d sometimes pass through each otherBox2d 中快速移动的物体有时会相互穿过
【发布时间】:2011-03-19 13:13:31
【问题描述】:

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

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

【问题讨论】:

  • 代码可能对我们有帮助
  • 我已经添加了相关代码。

标签: cocos2d-iphone box2d-iphone


【解决方案1】:

让我进一步详细说明 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
}

【讨论】:

  • 谢谢,但我已经尝试过使用这些值。最初它们分别是 10 和 1。我也试过 20,20。在应用线性脉冲之前,我还尝试从速度矢量修剪速度。但没有取得重大成功。而且这种传递行为只是偶尔发生,而不是始终发生。
  • 它确实增加了碰撞的敏感性,但起初所有的物体都开始疯狂移动。我尝试使用 substeps=2、不同的刻度间隔和增加物体的密度来平衡运动,但无法达到预期的效果。此外,它还会影响所有其他计时器和循环控件。
  • 尝试了几件事的可变值我终于找到了所需的运动和碰撞。 substeps=2 就足够了。谢谢你。顺便说一句,你不是“新手”编码员,所以请给自己一个正义:)
  • 双倍速度迭代和位置迭代对我来说效果不如每次更新调用 world.step 两次。谢谢!
  • 实际上将 velocityIterations 和 positionIterations 设置为 1 并让 step 运行两次对我来说比将 velocityIterations 和 positionIterations 设置为 5 并运行 step 运行得更好(阻止我的身体相互移动)。也许这与我的 targetFPS 为 30 有关。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2018-07-05
    相关资源
    最近更新 更多