【问题标题】:C++ Collision Detection causing objects to disappearC ++碰撞检测导致对象消失
【发布时间】:2017-04-07 05:29:07
【问题描述】:

我目前正在研究一些基本的 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 类物理代码都是我的。

编辑: 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;
}

【问题讨论】:

  • 您应该进行一些调试并报告您的发现。
  • 您需要提供正确的minimal reproducible example。特别是,我们需要知道NormVector 在代码层面上做了什么,以及OnCollision 做了什么。到目前为止,这些看起来是最有可能的罪魁祸首。
  • 对不起!将添加更多细节。
  • @Xirema 现在一切都好吗? :)

标签: c++ collision-detection game-physics


【解决方案1】:

我看到的一个问题是NormVector 的向量为零。您将除以零,在返回的向量中生成 NaN。当diffdiffContrained 相同时,这可能会在您现有的代码中发生,因此colCheck 将是(0,0) 导致VDirNorm 在其中包含NaN,这将传播到m_position

通常,归一化零长度向量应保持零长度向量(请参阅this post),但在这种情况下,由于您使用归一化向量在碰撞后偏移身体,因此您需要添加以合理的方式处理它的代码。

【讨论】:

  • 哦,哇,我不完全确定我会如何解决这个问题,但你是完全正确的,我会看看我能做什么,看看这是否是问题所在!谢谢!
  • 我倾向于认为 NaN 是对归一化零向量的完全有效的响应(尽管 OP 仍然需要更改代码以避免首先在零向量上调用归一化)但是基于This Post,听起来归一化零向量的正确方法是保持不变。所以我可能会将其添加到答案中。
  • 经过一些小调试后您完全正确,当 colCheck 为 0,0 时会发生这种情况。发生这种情况时,我尝试将 VDirNorm 保持为 0,0,但同样的问题发生了。解决这个问题可能很难!但是感谢您指出这一点!
  • 成功了!将结果添加到问题中!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-24
  • 1970-01-01
  • 2015-12-04
  • 2017-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多