如何确定矩形的哪一侧与圆碰撞 [英] How to determine which side of a rectangle collides with a circle

查看:99
本文介绍了如何确定矩形的哪一侧与圆碰撞的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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



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



仅供参考,我也看过向量归一化...我以前没有使用过它,所以请原谅我可以使用此方法解决... / p>

非常感谢您阅读



像我匆忙编辑一样,我改用了另一张图片...这仍然显示了我要实现的行为,因为图中所示的物理原理是我希望球在其运动时的行为与对方碰撞...
图像链接: http://codeincomplete.com/posts/2011/6/12/collision_detection_in_breakout/bounce2.v283.png

解决方案

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



这是一个图形,可以直观地帮助您执行代码。
红色圆圈与黑色矩形相交。可视化两条通过相对角的假想线。如果您知道圆在2条线的每一边上,则可以推断出发生碰撞的边缘。





首先声明类范围的私有成员

  Rectangle CollisionBoxRect; 
Rectangle circleRect;
Dictionary< string,Vector2>角落

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

 如果(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)
{
//顶部边缘与
相交return -Vector2.UnitY;
}
else
{
//右边缘相交的
return Vector2.UnitX;
}
}
else
{
if(isAboveDB)
{
//左边缘相交
return -Vector2 .UnitX;
}
else
{
//底边相交的
return Vector2.UnitY;
}
}
}






  public bool isOnUpperSideOfLine(Vector2 corner1,Vector2对角,Vector2 ballCenter)
{
return((oppositeCorner.X-corner1.X)*(ballCenter .Y-corner1.Y)-(Corner.Y-corner1.Y)*(ballCenter.X-corner1.X))> 0;
}






  private Vector2 getBallCenter()
{
返回新的Vector2(circleRect.Location.X + circleRect.Width / 2,circleRect.Location.Y + circleRect.Height / 2);
}






  private void getCorners(Rectangle boxToGetFrom)
{
corners.Clear();
Vector2 tl =新的Vector2(boxToGetFrom.X,boxToGetFrom.Y);
Vector2 tr =新的Vector2(boxToGetFrom.X + boxToGetFrom.Width,boxToGetFrom.Y);
Vector2 br = new Vector2(boxToGetFrom.X + boxToGetFrom.Width,boxToGetFrom.Y + boxToGetFrom.Height);
Vector2 bl =新的Vector2(boxToGetFrom.X,boxToGetFrom.Y + boxToGetFrom.Height);
corners.Add( topLeft,tl);
corners.Add( topRight,tr);
corners.Add( bottomRight,br);
corners.Add( bottomLeft,bl);
}


Before you point out that there are other answers to this question, i have looked at if not all, most of the other answers to this question or a similar question and i haven't found the solution i require.

Basically all i want to be able to do is when the circle/ball collides with a rectangle, i want to determine which side of the rectangle this collision has occured at. I want to find this out so that i can enforce a bit more realistic physics, e.g. if the ball hits the top of the rectangle, inverse it's Y velocity only... instead of both.

I have tried comparing the X and Y positions of the ball and the rectangle and even the location of both of their bounding boxes... testing even if the bottom of the ball's box has intersected with the rectangles top... using 'if ball.boundingBox.Bottom >= rectangle.boundingBox.Top'.

I have attached a picture to this to show what i am trying to achieve... just in case it's a bit confusing, as it's not detailed... the red what look like v's is the path if the ball comes in from one side, i want the movement upon impact to travel in the opposite way but this depends on the side of the rectangle as to what component of the ball's velocity i will have to change...

FYI i have also looked at vector normalisation... i haven't used it before so forgive me if this could be solved using this...

Thanks v.much for reading

EDIT as i am in a rush, i have used an different image instead... this still shows the behaviour i am trying to achieve, as the physics shown on the diagram is how i want the ball to behave when it collides with the other sides... LINK TO IMAGE: http://codeincomplete.com/posts/2011/6/12/collision_detection_in_breakout/bounce2.v283.png

解决方案

This code might be more comprehensive than you need and can be refactored to suit your needs but it is a complete answer and is flexible to use with moving bounding rectangles along with moving circles.

here is a graphic to give a visual aid to what the code is doing. the red circle is intersecting with the black rectangle. visualize two imaginary lines going through opposite corners. If you know which side of each of the 2 lines the circle is on, you can deduce the collided edge.

first declare class scope private members

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

In your update after you've moved the circle and set its location and the potential intersected box's location it does a basic check to see if the circle's bounding rect is involved with the block's bounding rect. If so, it then alters the ball's velocity with the appropriate collision normal depending on which side of the rect the circle collided with.

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

The following methods support getting the proper side (the normal actually). Some of these methods can be done once in the initialize phase if they never change (like the get corners method);

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

这篇关于如何确定矩形的哪一侧与圆碰撞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆