如何在一夫一妻制中创建一个圆变量并检测与其他圆/矩形的碰撞

本文关键字:检测 变量 其他 碰撞 一个 一夫一妻制 创建 | 更新日期: 2023-09-27 18:11:16

我想做一个效果区功能。到目前为止,我通过检查一个矩形是否与另一个矩形相交来管理碰撞。

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

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

如何在一夫一妻制中创建一个圆变量并检测与其他圆/矩形的碰撞

碰撞检测和响应可能是一个复杂的主题。然而,如果你只需要一些基本的碰撞类型,计算是相当容易的。

注意,一旦你开始涉及旋转和比圆形和矩形更复杂的形状,事情就会变得有点棘手。此外,这取决于在检测到碰撞后您想要做什么。移动的形状比静止的形状需要更多的工作。

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

话虽如此,让我们来分析一下计算方法。

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

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类。

然而,你可能也在这个过程中意识到,现在实际上有几种不同的碰撞组合。圆-圆,矩形-矩形,矩形-圆,有时用一个相反的圆-矩形也很方便。如果您将所有这些方法放在实际的形状类上,这可能会变得非常棘手(并且感觉错误)。我所见过的大多数物理引擎通常都有一些碰撞辅助类,将所有这些方法拉入一个静态类中。

祝你好运。

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

被接受的答案在角落生成处有错误:

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

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

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

你还需要检查圆的中心点是否在矩形内,因为这将被视为碰撞,即使两个部分没有重叠在圆上。

段与圆碰撞的数学计算应该很容易通过搜索来追踪。