如何在Monogame中创建圆形变量并检测与其他圆/矩形的碰撞

时间:2014-07-03 17:07:06

标签: c# xna monogame

我正在努力制作一个效果区域功能。到目前为止,我通过检查一个矩形是否与另一个矩形相交来管理碰撞。

这很简单,因为我只创建2个Rectangle变量并检查它们是否相交。但是,我似乎找不到一种简单的方法来创建Circle变量。

如何创建半径为r的圆,然后检查是否有任何矩形/圆与之相交?

3 个答案:

答案 0 :(得分:2)

碰撞检测和响应可能是一个复杂的主题。但是,如果您只需要一些基本的碰撞类型,则计算非常简单。

注意,一旦你开始涉及比圆形和矩形更复杂的旋转和形状,事情会变得有点毛茸茸。此外,它取决于检测到碰撞后您要执行的操作。移动形状比固定形状需要更多的工作。

如果你确实需要这些更复杂的东西,我建议看一下像Farseer Physics或Box2D.XNA这样的物理引擎。

那就是说,让我们分解计算。

如你所说,2个矩形之间的碰撞检测非常简单:

var rectangle1 = new Rectangle(100, 200, 300, 400);
var rectangle2 = new Rectangle(150, 250, 350, 450);

if(rectangle1.Intersects(rectangle2))
{
    // do your thing
}

现在,假设我们创建了一个类似行为的Circle类。

public struct Circle
{
    public Circle(int x, int y, int radius)
        : this()
    {
        X = x;
        Y = y;
        Radius = radius;
    }

    public int Radius { get; private set; }
    public int X { get; private set; }
    public int Y { get; private set; }

    public bool Intersects(Rectangle rectangle)
    {
        // the first thing we want to know is if any of the corners intersect
        var corners = new[]
        {
            new Point(rectangle.Top, rectangle.Left),
            new Point(rectangle.Top, rectangle.Right),
            new Point(rectangle.Bottom, rectangle.Right),
            new Point(rectangle.Bottom, rectangle.Left)
        };

        foreach (var corner in corners)
        {
            if (ContainsPoint(corner))
                return true;
        }

        // next we want to know if the left, top, right or bottom edges overlap
        if (X - Radius > rectangle.Right || X + Radius < rectangle.Left)
            return false;

        if (Y - Radius > rectangle.Bottom || Y + Radius < rectangle.Top)
            return false;

        return true;
    }

    public bool Intersects(Circle circle)
    {
        // put simply, if the distance between the circle centre's is less than
        // their combined radius
        var centre0 = new Vector2(circle.X, circle.Y);
        var centre1 = new Vector2(X, Y);
        return Vector2.Distance(centre0, centre1) < Radius + circle.Radius;
    }

    public bool ContainsPoint(Point point)
    {
        var vector2 = new Vector2(point.X - X, point.Y - Y);
        return vector2.Length() <= Radius;
    }
}

现在,如果我的计算结果正确(我把它写成了我的头脑),你应该可以像使用XNA / MonoGame Rectangle类一样使用新的Circle类。

但是,您可能还意识到现在实际上存在一些不同的碰撞组合。圆形圆形,矩形矩形,矩形圆形,有时可以方便地使用反转的圆形矩形。如果将所有这些方法放在实际的形状类上,这可能会非常难以管理(并且感觉不对)。我见过的大多数物理引擎通常都有一些碰撞助手类,它们将所有这些方法都集成到一个静态类中。

祝你好运:)如果我犯了任何错误,请告诉我。

答案 1 :(得分:2)

我还没有发表评论的声誉,所以我将通过答案发布它:

可接受的答案在角落产生错误:

 var corners = new[]
        {
            new Point(rectangle.Top, rectangle.Left),
            new Point(rectangle.Top, rectangle.Right),
            new Point(rectangle.Bottom, rectangle.Right),
            new Point(rectangle.Bottom, rectangle.Left)
        };

每个点的坐标都反转了!这将导致“镜面”碰撞检查,换句话说,如果在x = 300且y = 200处有子弹,则检查将在x = 200和y = 300处返回true。 它还会在正确的位置返回true,因为最后会返回true来管理未知案件。

因此,要解决其他问题,您需要具备以下条件:

var corners = new[]
            {
            new Point(rectangle.Left, rectangle.Top),
            new Point(rectangle.Right, rectangle.Top),
            new Point(rectangle.Right, rectangle.Bottom),
            new Point(rectangle.Left, rectangle.Bottom)
            };

答案 2 :(得分:0)

您可能需要创建自己的Circle类,其位置和半径。

关于圆与矩形之间的碰撞,我所做的就是将矩形分成四段。然后检查圆圈是否与四个段中的任何一个相交。这是通过检查从圆心到段的距离,并查看距离是否小于圆的半径来完成的。

您还需要检查圆的中心点是否在矩形内,因为即使这些线段不与圆重叠,也会被视为碰撞。

通过搜索可以很容易地跟踪分段与圆形碰撞的数学运算。

相关问题