撞击点:圆碰撞
本文关键字:碰撞 撞击 | 更新日期: 2023-09-27 18:03:08
我正在做一个关于机器人世界杯的学校项目,机器人和人工智能一起踢足球。虽然一切都很好,但我还是被一些东西卡住了。
机器人是从俯视图绘制的简单球体。两个玩家都不应该被允许撞到对方,并且应该在撞击点得到一个新的更新位置。
因为碰撞处理程序只是检查它们是否碰撞。我希望是否有办法检测到圆在哪里碰撞。所以我可以将碰撞球体的位置更新到最后一个已知的非碰撞位置,这样它们就不会穿过彼此,可能会反弹。
圆周上的所有点到圆心的距离(即半径)是相同的。对于赛场上的每个圆圈都是如此。
因此:当两个圆的中心之间的距离=它们各自半径的和时,恰好发生碰撞
嗯,你已经标记了一个答案,但是我去整理了一段功能完整的代码,所以也许你可以使用它。:)从我的评论:
因为它们只是圆,所以只需计算它们之间的中点圆圈的中心点。如果圆的半径不同,选择一个圆,并计算沿直线一个半径的点它的中心。
这可能是一个简单的实现。我为它创建了一些非常简陋的帮助类;我完全鼓励对它们进行扩展,使结构真正不可变,以及诸如此类的好东西,但目前用于演示目的还可以。
所以对于helper类:
public struct Point
{
public double X;
public double Y;
public double Distance(Point otherPoint)
{
double deltaX = this.X - otherPoint.X;
double deltaY = this.Y - otherPoint.Y;
return System.Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
}
public override string ToString()
{
return String.Format("({0}, {1})", X, Y);
}
}
public struct Polar
{
public double Radius;
public double Angle;
public double X { get { return Radius * System.Math.Cos(Angle); } }
public double Y { get { return Radius * System.Math.Sin(Angle); } }
public Point ToCartesian()
{
return new Point() { X = X, Y = Y };
}
}
public class Circle
{
public double Radius { get; set; }
public Point Position { get; set; }
}
我们的肉和土豆类/方法是这样的:
public class CollisionResult
{
public Circle Circle1 { get; private set; }
public Circle Circle2 { get; private set; }
public Point Circle1SafeLocation { get; private set; }
public Point Circle2SafeLocation { get; private set; }
public Point CollisionLocation { get; private set; }
public CollisionResult(Circle circle1, Circle circle2)
{
this.Circle1 = circle1;
this.Circle2 = circle2;
}
public bool CalculateCollision()
{
double distanceFromCentres = Circle1.Position.Distance(Circle2.Position);
if (distanceFromCentres >= Circle1.Radius + Circle2.Radius)
return false;
double angleBetweenCircles = System.Math.Atan2(Circle2.Position.Y - Circle1.Position.Y, Circle2.Position.X - Circle1.Position.X);
Point midpointBetweenCircles = new Point(){X = (Circle1.Position.X + Circle2.Position.X)/2, Y = (Circle1.Position.Y + Circle2.Position.Y)/2};
Point circle1Offset = (new Polar() { Radius = Circle1.Radius, Angle = System.Math.PI + angleBetweenCircles }).ToCartesian();
Point circle2Offset = (new Polar() { Radius = Circle2.Radius, Angle = angleBetweenCircles }).ToCartesian();
CollisionLocation = midpointBetweenCircles;
Circle1SafeLocation = new Point(){X = midpointBetweenCircles.X + circle1Offset.X, Y = midpointBetweenCircles.Y + circle1Offset.Y };
Circle2SafeLocation = new Point(){X = midpointBetweenCircles.X + circle2Offset.X, Y = midpointBetweenCircles.Y + circle2Offset.Y };
return true;
}
}
用法如下:
private void CheckCollision(Circle circle1, Circle circle2)
{
CollisionResult result = new CollisionResult(circle1, circle2);
if (result.CalculateCollision())
{
Console.WriteLine(String.Format("Collision detected at {0}! Safe location for circle 1: {1}, circle 2: {2}", result.CollisionLocation, result.Circle1SafeLocation, result.Circle2SafeLocation));
}
else
{
Console.WriteLine("Did not collide.");
}
}
var circle1 = new Circle() {Radius = 5, Position = new Point(){X = 0, Y = 0} };
var circle2 = new Circle() {Radius = 5, Position = new Point(){X = 10, Y = 0} };
var circle3 = new Circle() {Radius = 3, Position = new Point(){X = 0, Y = 1} };
var circle4 = new Circle() {Radius = 5, Position = new Point(){X = 3, Y = 7} };
CheckCollision(circle1, circle2);
CheckCollision(circle3, circle4);
输出:
Did not collide.
Collision detected at (1.5, 4)! Safe location for circle 1: (0.158359213500125, 1.31671842700025), circle 2: (3.73606797749979, 8.47213595499958)
我不知道在你的情况下是否有必要处理计算两个圆的真正交点(它们将在两点相交)之类的复杂性。很可能这些东西对你来说就足够了。我绝对鼓励健康的单元测试,并使类正确超出我在这里所做的。:)
编辑:在这种情况下,重要的是,这将取决于您想要在应用程序中对它做什么,当圆圈重叠时,它只是计算它们之间的中点,然后将每个圆圈从它们各自半径的中点移动。因此,根据圆的速度和大小,或者它们的运动方式,可能会产生奇怪的结果。例如,如果你有一个大的半径为10的圆静止不动,那么你扔一个半径为1的圆,距离大圆中心只有0.5的距离,这个大圆将移动大约9.75个单位!如果你没有遇到大的重叠情况,那么这可能不是什么大问题。我认为这至少会给你一些关于碰撞的信息然后你希望你的圆圈如何反应,结果将取决于你。
你需要做的是找到两个圆之间的交点,它可以是两个点,一个点,或者没有。这基本上是通过一起解两个圆的方程来完成的。计算方法如下:
http://www.analyzemath.com/CircleEq/circle_intersection.html由于这是学校的,我将把编码留给你:)