C# 绕圈碰撞以防止它们相互穿过
只是做了一点理论来简化我的问题。。我想知道这样做是否可行或更简单 我正在用C#做一个游戏模拟,机器人用人工智能踢足球。但是需要防止他们相互碰撞,找到准确的碰撞点来更新他们的位置,这样他们就不会相互碰撞 谢谢 这不是重复,因为我在问另一个我正在研究的理论。 好吧,从你的回答来看,你有什么不明白或需要帮助的地方吗?它几乎完全符合你的要求(所以“是的,你可以像这样使用极坐标”) 然而,你对“最后一个已知的没有碰撞的位置”的评论意味着你必须跟踪它们的位置,保持它们最后的良好状态并恢复到它。不确定在这种情况下是否有必要,或者您是否愿意只计算一个新的“最佳匹配”位置C# 绕圈碰撞以防止它们相互穿过,c#,collision,geometry,C#,Collision,Geometry,只是做了一点理论来简化我的问题。。我想知道这样做是否可行或更简单 我正在用C#做一个游戏模拟,机器人用人工智能踢足球。但是需要防止他们相互碰撞,找到准确的碰撞点来更新他们的位置,这样他们就不会相互碰撞 谢谢 这不是重复,因为我在问另一个我正在研究的理论。 好吧,从你的回答来看,你有什么不明白或需要帮助的地方吗?它几乎完全符合你的要求(所以“是的,你可以像这样使用极坐标”) 然而,你对“最后一个已知的没有碰撞的位置”的评论意味着你必须跟踪它们的位置,保持它们最后的良好状态并恢复到它。不确定在这种情
嗯,您已经标记了一个答案,但我去整理了一段功能完整的代码,所以您可能仍然可以使用它。:)根据我的评论: 因为它们只是圆,所以只需计算 圆的中心点。如果圆的半径不同,请选择 一个圆,并沿距离一个半径的直线计算点 它的中心 这可能是一个简单的实现。我为它创建了一些非常贫乏的助手类;我完全鼓励扩展它们,使结构真正不可变,所有这些都是很好的jazz,但现在可以用于演示目的 因此,对于助手类:
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个单位!如果你没有遇到大的重叠情况,那么这可能不是什么大问题。我想这至少会给你一些关于碰撞的信息,然后你想让你的圆圈做出怎样的反应将取决于你。好吧,从你的答案来看,你有什么不明白或需要帮助的地方吗?它几乎完全符合你的要求(所以“是的,你可以像这样使用极坐标”)
然而,你对“最后一个已知的没有碰撞的位置”的评论意味着你必须跟踪它们的位置,保持它们最后的良好状态并恢复到它。不确定在这种情况下是否有必要,或者您是否愿意只计算一个新的“最佳匹配”位置
嗯,您已经标记了一个答案,但我去整理了一段功能完整的代码,所以您可能仍然可以使用它。:)根据我的评论: 因为它们只是圆,所以只需计算 圆的中心点。如果圆的半径不同,请选择 一个圆,并沿距离一个半径的直线计算点 它的中心 这可能是一个简单的实现。我为它创建了一些非常贫乏的助手类;我完全鼓励扩展它们,使结构真正不可变,所有这些都是很好的jazz,但现在可以用于演示目的 因此,对于助手类:
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个单位!如果你没有遇到大的重叠情况,那么这可能不是什么大问题。我认为,至少这会给你一些关于碰撞的信息,然后你希望你的圆圈如何反应将取决于你。可能是这样,这对你有帮助:
本教程由四个部分组成,非常好地解释了二维动力学。这可能对您有所帮助:
本教程由四个部分组成,非常好地解释了二维动力学。查看两个圆是否碰撞的更快方法是不断检查它们的位置。事实上,你必须检查他们中心之间的距离是否小于他们半径的总和 一些“伪代码”可能是:
distanceX = Math.Abs(circle1.X - cirlce2.X);
distanceY = Math.Abs(circle1.Y - cirlce2.Y);
distance = Math.Sqrt(distanceX * distanceX - distanceY * distanceY);
if(distance <= circle1.Radius + circle2.Radius){
//they're colliding and the point of collision is:
collisionX = distanceX / 2;
collisionY = distanceY / 2;
if(circle1.X < circle2.X)
collisionX += circle1.X;
else
collisionX += circle2.X;
if(circle1.Y < circle2.Y)
collisionY += circle1.Y;
else
collisionY += circle2.Y;
}
distanceX=Math.Abs(circle1.X-cirlce2.X);
距离Y=数学值Abs(圆圈1.Y-cirlce2.Y);
距离=数学.Sqrt(