2013-11-01 70 views
4

我想限制身體可以行駛的最高速度。其實限制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 accumulator進行步進時力會如何影響速度,我不知道當前需要多少物理步驟。

除了在Box2D源代碼中集成位置之前直接限制速度,有什麼辦法可以解決這個問題嗎?

+1

爲什麼不簡單總結施加的力量,而是每一步,只適用於您的首選最大值(並通過max降低applied_force)。 – Wilbert

+0

爲什麼不在時間步之後進行夾緊? – iforce2d

回答

1

我對解決這個問題的首次嘗試是通過簡單地執行的代碼上述作品並不是每一個,但每物理分步驟,這意味着如果我delta accumulator告訴我,我必須執行ňb2World::Step的,我也上限速度ñ時間:

// 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的\動態\ b2Body.h
  2. 添加float32 m_max_speed公共成員並初始化它與-1.f所以最初我們不限制任何身體的速度。
  3. 轉到Box2D \ Dynamics \ b2Island.cpp。
  4. 找到行號222
  5. 添加以下如果條件

    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; 
    

這將工作即使沒有substepping是我上面描述,但請記住,如果你模擬空氣阻力,應用拖曳力每個子步驟保證模擬的正確性,即使幀頻變化。

1

首先,爲自己回答,誰可以對身體施加武力。 Box2D本身可以通過接觸和重力影響人體。聯繫人不是使用武力,而是衝動。管理他們設置聯繫人偵聽器並修改normalImpulses and tangentImpulses。重力我認爲不能影響身體很多,但它也可以通過b2BodyDef :: gravityScale進行控制。 如果你的代碼附加了一些手動的力量,那麼引入一些代理接口來管理它們可能是有用的。

我不能看到一些簡單的方法,因爲在每一步box2d進行幾次速度和位置迭代。所以,在步驟開始時施加的力量和衝動將相應地導致位置的改變。

我無法想象的方式,如何嚴格的速度沒有黑客box2d源代碼。順便說一句,我認爲這是不錯的變種。例如,將Dynamics/b2Island.cpp:219(b2Island :: Solve)中的限制插入w和v變量。