【问题标题】:How to determine which side of a rectangle collides with a circle如何确定矩形的哪一侧与圆相撞
【发布时间】:2013-10-05 13:29:06
【问题描述】:

在您指出此问题还有其他答案之前,我已经查看了此问题或类似问题的大多数其他答案(如果不是全部),但我还没有找到我需要的解决方案。

基本上我想做的就是当圆/球与矩形碰撞时,我想确定碰撞发生在矩形的哪一侧。我想找出这一点,以便我可以执行更现实的物理,例如如果球击中矩形的顶部,则仅反转它的 Y 速度...而不是两者。

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

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

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

非常感谢阅读

编辑,因为我很匆忙,我使用了不同的图像......这仍然显示了我试图实现的行为,因为图表上显示的物理是我希望球在碰撞时的行为与对方... 图片链接:http://codeincomplete.com/posts/2011/6/12/collision_detection_in_breakout/bounce2.v283.png

【问题讨论】:

    标签: c# xna collision-detection game-physics


    【解决方案1】:

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

    这是一个图形,可以直观地帮助代码正在执行的操作。 红色圆圈与黑色矩形相交。想象两条穿过对角的假想线。如果你知道圆在 2 条线的哪一边,你就可以推断出碰撞的边缘。

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

    Rectangle CollisionBoxRect;
    Rectangle circleRect;
    Dictionary<string, Vector2> corners;
    

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

    if (CollisionBoxRect.Intersects(circleRect))
    {
         ballVelocity = Vector2.Reflect(ballVelocity, GetCollisionNormal(CollisionBoxRect));
    }
    

    以下方法支持获取正确的一面(实际上是正常的)。其中一些方法可以在初始化阶段执行一次,如果它们永远不会改变(如 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;
            }
        }
    }
    

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

    private Vector2 getBallCenter()
    {
        return new Vector2(circleRect.Location.X + circleRect.Width / 2, circleRect.Location.Y + circleRect.Height / 2);
    }
    

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

    【讨论】:

    • 哇,非常感谢您的深入回复。抱歉,我刚刚才意识到我收到了对这篇文章的回复……我会仔细查看并尝试在我的代码中实现它,因为我仍然有同样的问题,但我今天刚刚恢复完成这个游戏。 ..我会让你知道会发生什么......非常感谢v
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-07
    • 2015-06-27
    • 2014-09-03
    • 2014-04-08
    • 1970-01-01
    • 2010-09-28
    相关资源
    最近更新 更多