2017-04-06 32 views
0

我目前正在研究一些基本的2D RigidBody物理並遇到問題。我有一個函數可以檢查Circle和AABB之間的碰撞,但有時Circle(在這種情況下是玩家)會碰撞然後消失,如果我在這種情況下打印出位置,我只需設置「nan」。C++碰撞檢測導致對象消失

bool Game::Physics::RigidBody2D::CircleAABB(RigidBody2D& body) 
{ 
    sf::Vector2f diff = m_Position - body.m_Position; 

    sf::Vector2f halfExtents = sf::Vector2f(body.m_Size.x/2.0f, body.m_Size.y/2.0f); 

    sf::Vector2f diffContrained = diff; 

    if (diff.x > halfExtents.x) 
    { 
     diffContrained.x = halfExtents.x; 
    } 
    else if (diff.x < -halfExtents.x) 
    { 
     diffContrained.x = -halfExtents.x; 
    } 
    if (diff.y > halfExtents.y) 
    { 
     diffContrained.y = halfExtents.y; 
    } 
    else if (diff.y < -halfExtents.y) 
    { 
     diffContrained.y = -halfExtents.y; 
    } 
    sf::Vector2f colCheck = diff - diffContrained; 
    sf::Vector2f VDirNorm = NormVector(colCheck); 
    sf::Vector2f colToPlayer = NormVector(m_Position - (diffContrained + body.m_Position)); 
    float dist = getMagnitude(colCheck) - m_fRadius; 
    //std::cout << dist << std::endl; 
    if (dist < 0) 
    { 
     OnCollision((diffContrained + body.m_Position) - m_Position); 
     m_Position += (VDirNorm * abs(dist)); 
     body.m_Position -= (VDirNorm * abs(dist))* (1.0f - body.m_fMass); 

     return true; //Collision has happened 
    } 
    return false; 
} 

出現這種情況隨機幾乎沒有明確的原因,雖然它似乎當圓快速移動更經常地發生,但是當它移動緩慢,或一個或兩個時候,它是不是在移動可能發生,以及所有。

的補充說明的是,我應用重力到Y速度和碰撞協調軸的速度設置爲0

所以我的問題是,是用得比較多的物理經驗的東西顯然是錯誤這裏的我?

注意:使用SFML繪圖和Vector2類物理代碼是我的。

編輯:OnCollision函數檢查側面碰撞,以便繼承的對象可以使用此(例如檢查碰撞是否在下面以觸發「isGrounded」布爾值)。在這種情況下,玩家檢查側面,然後將該軸上的速度設置爲0,並在下面時觸發isGrounded布爾值。

void Game::GamePlay::PlayerController::OnCollision(sf::Vector2f vDir) 
{ 

if (abs(vDir.x) > abs(vDir.y)) 
    { 
     if (vDir.x > 0.0f) 
     { 
      //std::cout << "Right" << std::endl; 
      //Collision on the right 
      m_Velocity.x = 0.0f; 
     } 
     if (vDir.x < 0.0f) 
     { 
      //std::cout << "Left" << std::endl; 
      //Collision on the left 
      m_Velocity.x = 0.0f; 
     } 
     return; 
    } 
    else 
    { 
     if (vDir.y > 0.0f) 
     { 
      //std::cout << "Below" << std::endl; 
      //Collision below 
      m_Velocity.y = 0.0f; 
      if (!m_bCanJump && m_RecentlyCollidedNode != nullptr) 
      { 
       m_RecentlyCollidedNode->ys += 3.f; 
      } 
      m_bCanJump = true; 
     } 
     if (vDir.y < 0.0f) 
     { 
      //std::cout << "Above" << std::endl; 
      //Collision above 
      m_Velocity.y = 0.0f; 

     } 
    } 
} 

從調試出來的速度和位置沒有真正的原因來到表面。

inline sf::Vector2f NormVector(sf::Vector2f vec) 
{ 
    float mag = getMagnitude(vec); 
    return vec/mag; 
} 

解決方案:

if (colCheck.x == 0 && colCheck.y == 0) 
{ 
    std::cout << "Zero Vector" << std::endl; 
    float impulse = m_Velocity.x + m_Velocity.y; 
    m_Velocity.x = 0; 
    m_Velocity.y = 0; 
    m_Velocity += NormVector(diff)*impulse; 
} 
else 
{ 
    VDirNorm = NormVector(colCheck); 
    dist = getMagnitude(colCheck) - m_fRadius; 
} 
+1

您應該進行一些調試並使用您發現的內容進行報告。 –

+1

你需要提供一個合適的[mcve]。特別是,我們需要知道'NormVector'在代碼級別上的功能,以及'OnCollision'的作用。到目前爲止,這些看起來像是最可能的罪魁禍首。 – Xirema

+0

對不起!將添加更多細節。 –

回答

2

一個問題我看到的是NormVector以零向量。您將除以零,在您的返回矢量中生成NaN。當diffdiffContrained相同時,這可能發生在您現有的代碼中,因此colCheck將(0,0)導致VDirNorm在其中存在NaN,這將傳播到m_position

通常情況下,歸一化的零長度向量應該保持零長度向量(請參閱this post),但在這種情況下,由於您使用歸一化向量在碰撞後偏移身體,因此需要添加代碼以合理的方式處理它。

+0

哦,哇,我不完全確定如何去解決這個問題,但你完全正確,我會看看我能做什麼,看看這是否是問題!謝謝! –

+0

我傾向於認爲NaN是一個對零矢量進行規範化的完全有效的響應(儘管OP仍然需要進行代碼更改以避免首先在零矢量上調用標準化),但是基於[本文]( http://stackoverflow.com/questions/722073/how-do-you-normalize-a-zero-vector),它聽起來像正常化零矢量的方法是保持不變。所以我可能會添加到答案。 – Xirema

+0

經過一些小的調試之後,您完全正確,這發生在colCheck爲0,0時。發生這種情況時,我嘗試將VDirNorm保持爲0,0,但同樣的問題發生。修復這可能很難!但是,謝謝你指出這一點! –