如何确定矩形的哪一边与圆形碰撞

6a6*_*179 1 c# xna collision-detection game-physics

在您指出这个问题还有其他答案之前,我已经查看了这个问题或类似问题的大多数其他答案,但我还没有找到我需要的解决方案。

基本上我想要做的就是当圆/球与矩形碰撞时,我想确定碰撞发生在矩形的哪一侧。我想找出这一点,以便我可以执行更逼真的物理效果,例如,如果球击中矩形的顶部,则仅将其反转为 Y 速度……而不是两者兼而有之。

我已经尝试比较球和矩形的 X 和 Y 位置,甚至它们两个边界框的位置......即使球的底部与矩形顶部相交也进行测试......使用'if ball .boundingBox.Bottom >= rectangle.boundingBox.Top'。

我附上了一张图片来展示我想要达到的目标......以防万一它有点混乱,因为它没有详细......如果球从一侧进入,红色看起来像 v 是路径,我希望撞击时的运动以相反的方式行进,但这取决于矩形的一侧,我将不得不改变球速度的哪个分量......

仅供参考,我也看过向量归一化……我以前没有使用过它,所以请原谅我,如果可以用这个来解决这个问题……

非常感谢阅读

编辑因为我很匆忙,我使用了不同的图像代替......这仍然显示了我试图实现的行为,因为图中显示的物理是我希望球与另一个碰撞时的行为侧面......图像链接:http : //codeincomplete.com/posts/2011/6/12/collision_detection_in_breakout/bounce2.v283.png

Ste*_*e H 5

此代码可能比您需要的更全面,并且可以重构以满足您的需要,但它是一个完整的答案,并且可以灵活地与移动边界矩形和移动圆一起使用。

这是一个图形,可以为代码正在做什么提供视觉帮助。红色圆圈与黑色矩形相交。想象两条穿过对角的假想线。如果您知道圆在 2 条直线的哪一边,您就可以推断出碰撞的边缘。

在此处输入图片说明

首先声明类作用域私有成员

Rectangle CollisionBoxRect;
Rectangle circleRect;
Dictionary<string, Vector2> corners;
Run Code Online (Sandbox Code Playgroud)

在您移动圆并设置其位置和潜在相交框的位置后的更新中,它会进行基本检查以查看圆的边界矩形是否与块的边界矩形有关。如果是这样,它将根据圆与矩形的哪一侧碰撞,以适当的碰撞法线改变球的速度。

if (CollisionBoxRect.Intersects(circleRect))
{
     ballVelocity = Vector2.Reflect(ballVelocity, GetCollisionNormal(CollisionBoxRect));
}
Run Code Online (Sandbox Code Playgroud)

以下方法支持获得正确的一面(实际上是正常的)。如果这些方法中的一些从不改变,则它们可以在初始化阶段完成一次(例如 get corners 方法);

private Vector2 GetCollisionNormal(Rectangle boxBeingIntersected)
{
    getCorners(boxBeingIntersected);
    bool isAboveAC = isOnUpperSideOfLine(corners["bottomRight"], corners["topLeft"], getBallCenter());
    bool isAboveDB = isOnUpperSideOfLine( corners["topRight"], corners["bottomLeft"], getBallCenter());

    if (isAboveAC)
    {
        if (isAboveDB)
        {
            //top edge has intersected
            return -Vector2.UnitY;
        }
        else
        {
            //right edge intersected
            return Vector2.UnitX;
        }
    }
    else
    {
        if (isAboveDB)
        {
            //left edge has intersected
            return -Vector2.UnitX;
        }
        else
        {
            //bottom edge intersected
            return Vector2.UnitY;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
public bool isOnUpperSideOfLine(Vector2 corner1, Vector2 oppositeCorner, Vector2 ballCenter)
{
    return ((oppositeCorner.X - corner1.X) * (ballCenter.Y - corner1.Y) - (oppositeCorner.Y - corner1.Y) * (ballCenter.X - corner1.X)) > 0;
}
Run Code Online (Sandbox Code Playgroud)
private Vector2 getBallCenter()
{
    return new Vector2(circleRect.Location.X + circleRect.Width / 2, circleRect.Location.Y + circleRect.Height / 2);
}
Run Code Online (Sandbox Code Playgroud)
private void getCorners(Rectangle boxToGetFrom)
{
    corners.Clear();
    Vector2 tl = new Vector2(boxToGetFrom.X, boxToGetFrom.Y);
    Vector2 tr = new Vector2(boxToGetFrom.X + boxToGetFrom.Width, boxToGetFrom.Y);
    Vector2 br = new Vector2(boxToGetFrom.X + boxToGetFrom.Width, boxToGetFrom.Y + boxToGetFrom.Height);
    Vector2 bl = new Vector2(boxToGetFrom.X, boxToGetFrom.Y + boxToGetFrom.Height);
    corners.Add("topLeft", tl);
    corners.Add("topRight", tr);
    corners.Add("bottomRight", br);
    corners.Add("bottomLeft", bl);
}
Run Code Online (Sandbox Code Playgroud)