1

只是做了一个小理论来简化我的问题。我想知道这样做是否可行或更简单的方法。

我正在用 C# 进行游戏模拟,机器人与 AI 一起踢足球。但是需要防止他们互相走入,找到确切的撞击点来更新他们的位置,这样他们就不会互相走入。

谢谢。

这不是重复的,因为我问的是我正在研究的另一个理论。

圆碰撞理论

4

3 回答 3

2

好吧,从我已经从您之前的问题中提供的答案中,您有什么不明白或需要帮助的吗?它几乎完全符合您在这里的要求(所以“是的,您可以像这样使用极坐标。”)

但是,您对“他们没有碰撞的最后一个已知位置”的评论意味着您必须跟踪他们的位置并保持他们最后的良好状态并恢复到它。不确定在这种情况下是否有必要,或者您是否只想计算一个新的“最合适”的位置。


好吧,你已经标记了一个答案,但我去整理了一段功能齐全的代码,所以也许你仍然可以使用它。:) 根据我的评论:

由于它们只是圆圈,因此只需计算圆圈中心点之间的中点即可。如果圆具有不同的半径,则选择一个圆并计算沿线距其中心一半径的点。

这可能是一个简单的实现。我为它创建了一些非常微薄的辅助类;我完全鼓励扩展它们,使结构真正不可变,以及所有那些好的爵士乐,但现在可以用于演示目的。

所以对于助手类:

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 的大圆静止不动,那么你在距离大圆中心仅 0.5 距离的地方投入一个半径为 1 的圆,那个大圆将移动大约 9.75 个单位!如果您没有遇到大的重叠条件,那么也许这不是什么大问题。我认为至少这会给你一些关于碰撞的信息,然后如何您是否希望您的圈子做出反应,结果将取决于您。

于 2013-03-10T16:14:34.013 回答
1

可能这对您有帮助: http ://www.emanueleferonato.com/2011/06/13/slicing-splitting-and-cutting-objects-with-box2d/

本教程由四部分组成,很好地解释了 2D 动力学。

于 2013-03-10T16:18:05.520 回答
1

查看两个圆圈是否碰撞的更快方法是不断检查它们的位置。事实上,您必须检查它们的中心之间的距离是否小于它们的半径之和。

一些“伪代码”可能是:

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

PS:Math.Pow()请注意,由于它的性能,我没有使用。

于 2013-03-10T16:40:22.950 回答