我正在努力制作一个效果区域功能。到目前为止,我通过检查一个矩形是否与另一个矩形相交来管理碰撞。
这很简单,因为我只创建2个Rectangle
变量并检查它们是否相交。但是,我似乎找不到一种简单的方法来创建Circle
变量。
如何创建半径为r
的圆,然后检查是否有任何矩形/圆与之相交?
答案 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类,其位置和半径。
关于圆与矩形之间的碰撞,我所做的就是将矩形分成四段。然后检查圆圈是否与四个段中的任何一个相交。这是通过检查从圆心到段的距离,并查看距离是否小于圆的半径来完成的。
您还需要检查圆的中心点是否在矩形内,因为即使这些线段不与圆重叠,也会被视为碰撞。
通过搜索可以很容易地跟踪分段与圆形碰撞的数学运算。