如何在一夫一妻制中创建一个圆变量并检测与其他圆/矩形的碰撞
本文关键字:检测 变量 其他 碰撞 一个 一夫一妻制 创建 | 更新日期: 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类,其中包含位置和半径。
关于圆和矩形之间的碰撞,我所做的是将矩形分成四个部分。然后检查圆是否与这四条线段中的任何一条相交。这是通过检查从圆心到线段的距离,并查看距离是否小于圆的半径来完成的。
你还需要检查圆的中心点是否在矩形内,因为这将被视为碰撞,即使两个部分没有重叠在圆上。
段与圆碰撞的数学计算应该很容易通过搜索来追踪。