2017-04-06 1 views
0

Ich arbeite gerade an einigen grundlegenden 2D RigidBody Physik und habe ein Problem festgestellt. Ich habe eine Funktion, die auf Kollision zwischen einem Kreis und einem AABB prüft, aber manchmal kollidiert der Kreis (in diesem Fall der Spieler) und verschwindet dann. Wenn ich die Position ausdruck, wenn dies passiert, setze ich einfach "nan".C++ Collision Detection verursacht das Verschwinden von Objekten

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; 
} 

Dies geschieht zufällig und fast ohne ersichtlichen Grund, obwohl es häufiger zu passieren scheint, wenn der Kreis schnell bewegt, kann aber auch passieren, wenn es langsam oder ein oder zwei Mal bewegt, wenn es überhaupt nicht bewegt alle.

Ein weiterer Hinweis ist, dass ich die Schwerkraft auf die Y-Geschwindigkeit und auf Kollision stellen Sie die Geschwindigkeit der koordinierenden Achse auf 0

Also meine Frage anzuwenden ist, ist etwas eindeutig falsch hier, um diejenigen mit mehr Physik Erfahrung als mich?

Hinweis: Die Verwendung von SFML zum Zeichnen und Vector2 Klassen Physik Code ist alles meins.

EDIT: Die OnCollision-Funktion prüft die Seite der Kollision, so dass Objekte, die erben, diese verwenden können (z. B. prüfen, ob die Kollision unterhalb war, um einen "isGrounded" -Boolean auszulösen). In diesem Fall überprüft der Spieler die Seite und setzt dann die Geschwindigkeit auf dieser Achse auf 0 und löst auch einen isGrounded-Boolean aus, wenn er darunter ist.

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; 

     } 
    } 
} 

Aus dem Debugging von Geschwindigkeit und Position ist kein wirklicher Grund an die Oberfläche gekommen.

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

Lösung:

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

Sie sollten einige Debugging und melden Sie zurück mit dem, was Sie finden. –

+1

Sie müssen eine ordnungsgemäße [MCVE] bereitstellen. Insbesondere müssen wir wissen, was "NormVector" auf Code-Ebene macht und was "OnCollision" tut. Bis jetzt sehen diese wie die wahrscheinlichsten Täter aus. – Xirema

+0

Entschuldigung! Wird mehr Details hinzufügen. –

Antwort

2

Ein Problem, das ich sehe, ist NormVector mit einem Nullvektor. Sie teilen durch Null und erzeugen NaNs in Ihrem zurückgegebenen Vektor. Dies kann in Ihrem vorhandenen Code passieren, wenn diff und diffContrained die gleichen sind, also wird colCheck (0,0) verursachen VDirNorm, um NaNs darin zu haben, die sich in m_position ausbreiten werden.

Normalerweise sollte ein normalisierter Nulllängenvektor ein Nulllängenvektor bleiben (siehe this post), aber in diesem Fall müssen Sie Code hinzufügen, da Sie den normalisierten Vektor zum Versetzen Ihrer Körper nach der Kollision verwenden um es vernünftig zu handhaben.

+0

Oh wow, ich bin mir nicht ganz sicher, wie ich das beheben würde, aber du hast vollkommen recht, ich werde sehen, was ich tun kann und sehen, ob das das Problem ist! Vielen Dank! –

+0

Ich bin geneigt zu argumentieren, dass NaNs eine vollkommen gültige Antwort auf die Normalisierung eines Zero-Vectors sind (obwohl OP immer noch Codeänderungen vornehmen muss, um das Aufrufen von Normalisierung auf einem Zero Vector zu vermeiden), aber basierend auf [This Post] (http://stackoverflow.com/questions/722073/how-do-you-normalize-a-zero-vector), es klingt wie der richtige Weg, um einen Nullvektor zu normalisieren ist es unverändert zu lassen. Also würde ich das wahrscheinlich zu der Antwort hinzufügen. – Xirema

+0

Nach einigem kleinen Debuggen sind Sie völlig korrekt, dies passiert, wenn colCheck 0,0 ist. Ich habe versucht, VDirNorm auf 0,0 zu halten, wenn das passiert, aber das gleiche Problem passiert. Dies zu beheben könnte schwierig sein! Aber danke, dass du darauf hingewiesen hast! –