C++ 碰撞检测导致对象消失
C++ Collision Detection causing objects to disappear
我目前正在研究一些基本的 2D 刚体物理学,运行 遇到了一个问题。我有一个检查 Circle 和 AABB 之间碰撞的功能,但有时 Circle(在这种情况下是玩家)会碰撞然后消失,如果我在发生这种情况时打印出位置,我只需设置 "nan".
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 class 物理代码都是我的。
编辑: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;
}
我看到的一个问题是 NormVector
零向量。您将除以零,在返回的向量中生成 NaN。当 diff
和 diffContrained
相同时,这可能会在您现有的代码中发生,因此 colCheck
将是 (0,0) 导致 VDirNorm
中包含 NaN,这将传播到 m_position
.
通常,归一化的零长度向量应保持为零长度向量(请参阅 this post),但在这种情况下,由于您在碰撞后使用归一化向量来抵消您的身体,您我们将需要添加代码以合理的方式处理它。
我目前正在研究一些基本的 2D 刚体物理学,运行 遇到了一个问题。我有一个检查 Circle 和 AABB 之间碰撞的功能,但有时 Circle(在这种情况下是玩家)会碰撞然后消失,如果我在发生这种情况时打印出位置,我只需设置 "nan".
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 class 物理代码都是我的。
编辑: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;
}
我看到的一个问题是 NormVector
零向量。您将除以零,在返回的向量中生成 NaN。当 diff
和 diffContrained
相同时,这可能会在您现有的代码中发生,因此 colCheck
将是 (0,0) 导致 VDirNorm
中包含 NaN,这将传播到 m_position
.
通常,归一化的零长度向量应保持为零长度向量(请参阅 this post),但在这种情况下,由于您在碰撞后使用归一化向量来抵消您的身体,您我们将需要添加代码以合理的方式处理它。