实际上限制Box2D的最大速度

时间:2013-11-01 12:25:51

标签: c++ box2d

我想限制身体可以随身携带的最高速度。

问题是,即使我做了类似this answer的建议:

/* after applying forces from input for example */
b2Vec2 vel = body->GetLinearVelocity();
float speed = vel.Normalize();//normalizes vector and returns length
if ( speed > maxSpeed ) 
    body->SetLinearVelocity( maxSpeed * vel );

如果,例如,在夹紧速度之前,我正在向身体施加一些巨大的力量? 即使线速度暂时限制在maxSpeed,在下一个时间步长Box2D将考虑b2Body :: m_force值并有效地移动我的身体比maxSpeed更快。

所以我想出了这个(必须将b2Body :: m_force移动到公共场所):

if ( speed > maxSpeed ) {
    body->SetLinearVelocity( maxSpeed * vel );
    body->m_force = b2Vec2(0, 0)
}

然而,这仍然无法正确处理问题。

如果速度略微小于maxSpeed,那么条件不会被击中,但是m_force值仍然足够大以增加速度?

关键是我无法准确预测力量如何影响速度,因为我使用delta累加器踩踏,我不知道目前需要多少物理步骤。

除了在Box2D源代码中积分位置之前直接限制速度之外,有没有办法解决这个问题?

2 个答案:

答案 0 :(得分:2)

我解决这个问题的第一个尝试是简单地执行上面的代码而不是每个循环,而是每个物理子步骤,这意味着如果我的{{3}告诉我,我必须执行 n b2World::Step,我还要限制速度 n 次:

// source code taken form above link and modified for my purposes
for (int i = 0; i < nStepsClamped; ++ i)
{
    resetSmoothStates_ ();

    // here I execute whole systems that apply accelerations, drag forces and limit maximum velocities
    // ...
    if ( speed > maxSpeed ) 
         body->SetLinearVelocity( maxSpeed * vel );
    // ...

    singleStep_ (FIXED_TIMESTEP);

    // NOTE I'M CLEARING FORCES EVERY SUBSTEP to avoid excessive accumulation
    world_->ClearForces ();
}

现在虽然这给了我恒定的速度而不管帧速率(这是我主要担心的,因为我的动作是紧张的),但并不总是<= maxSpeed。同样的情况:想象一下在加速和b2World::Step之前施加的巨大力量。

现在,我可以简单地计算根据当前速度应用的实际力,因为我知道力只会被应用一次直到下一次验证,但还有另一个简单的解决方案,我已经提到并最终坚持:

  1. 转到Box2D \ Dynamics \ b2Body.h
  2. 添加float32 m_max_speed公开成员并使用-1.f对其进行初始化,因此我们最初不会限制任何正文的速度。
  3. 转到Box2D \ Dynamics \ b2Island.cpp。
  4. 找到第222行。
  5. 添加以下 if condition

    m_positions[i].c = c;
    m_positions[i].a = a;
    
    if (b->m_max_speed >= 0.f) {
        float32 speed = v.Normalize();
        if (speed > b->m_max_speed)
            v *= b->m_max_speed;
        else v *= speed;
    }
    
    m_velocities[i].v = v;
    m_velocities[i].w = w; 
    
  6. 即使没有我上面描述的子步骤也可以工作但请记住,如果你要模拟空气阻力,每个子步骤施加阻力保证正确性即使使用不同的帧速率也能进行模拟。

答案 1 :(得分:1)

首先,回答自己,谁可以对身体施加力量。 Box2D本身可以通过接触和重力影响身体。联系人不是使用武力,而是使用冲动。要管理它们,请设置联系人侦听器并修改normalImpulses and tangentImpulses 。重力我认为不能影响身体很多,但它也可以通过b2BodyDef :: gravityScale控制。 如果您的代码使用了一些手动力量,那么引入一些代理接口来管理它们可能很有用。

我看不出一些简单的方法,因为在每一步中,box2d会进行多次速度和位置迭代。因此,在步骤开始时施加于其上的力和冲动将相应地引起位置的改变。

我无法想象的方式,如何严格的速度没有黑客box2d源代码。顺便说一句,我认为这是不错的变种。例如,将Dynamics / b2Island.cpp:219(b2Island :: Solve)中的限制插入到w和v变量中。