5

我想限制一个身体可以旅行的最大速度。

问题是,即使我做了类似这个答案建议的事情:

/* 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 值仍然足够大,足以使速度增加太多怎么办?

关键是当我使用增量累加器步进时,我无法准确预测力将如何影响速度,而且我不知道目前需要多少物理步骤。

除了在 Box2D 源代码中集成位置之前直接限制速度之外,还有什么方法可以解决这个问题?

4

2 回答 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 条件

    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; 
    

即使没有我上面描述的子步,这也可以工作,但请记住,如果您要模拟空气阻力,即使在不同的帧速率下,每个子步都施加阻力可以保证模拟的正确性。

于 2013-11-03T16:34:10.747 回答
1

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

我看不到一些简单的方法,因为在每一步 box2d 都会进行几次速度和位置迭代。因此,在步骤开始时施加在其上的力和冲量将相应地导致位置变化。

我无法想象在不破解 box2d 源代码的情况下,速度有多严格。顺便说一句,我认为这是不错的变体。例如,将 Dynamics/b2Island.cpp:219 (b2Island::Solve) 中的限制插入到 w 和 v 变量。

于 2013-11-01T18:08:26.503 回答