1

私の問題を単純化するために少し理論を作っただけです..これが可能か、それとも簡単な方法か知りたいです。

ロボットが AI でサッカーをするゲーム シミュレーションを C# で作成しています。しかし、彼らがお互いに歩み寄るのを防ぐ必要があり、衝突の正確なポイントを見つけて位置を更新し、お互いに歩み寄ることができないようにする必要があります.

ありがとう。

私が取り組んでいた別の理論を尋ねていたので、これは重複していません。

円衝突理論

4

3 に答える 3

2

さて、あなたの前の質問から私がすでに提供した答えから、あなたが理解できないことや助けが必要なことはありますか? それはあなたがここで求めていることをほぼ正確に行います(したがって、「はい、このような極座標を使用できます。」)

ただし、「衝突しなかった最後の既知の位置」についてのコメントは、それらの位置を追跡し、最後の良好な状態を維持して元に戻す必要があることを意味します。この場合にそれが必要なのか、それとも新しい「最適な」場所を計算するだけなのかはわかりません。


さて、あなたはすでに回答をマークしましたが、私は完全に機能するコードをまとめたので、とにかくそれを使用できるかもしれません. :)私のコメントから:

それらは単なる円なので、円の中心点の間の中点を計算するだけです. 円の半径が異なる場合は、1 つの円を選択し、その中心から半径 1 つ離れた線に沿った点を計算します。

これは単純な実装かもしれません。そのための非常に貧弱なヘルパー クラスをいくつか作成しました。それらを拡張し、構造体を真に不変にすること、およびすべての優れたジャズを作成することを強くお勧めしますが、今のところ、デモンストレーションの目的には問題ありません。

したがって、ヘルパー クラスの場合:

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)

あなたの場合、2つの円の真の交点(2点で交差する場所)などを計算する複雑さに対処する必要があるかどうかはわかりません。これらの線に沿ったもので十分でしょう。私は間違いなく健全な単体テストを奨励し、ここにあるものを超えて適切なクラスを作成します。:)

この場合、これはアプリケーションで何をしたいかによって異なりますが、円が重なっている場合、それらの間の中点を計算し、円をその中点からそれぞれの半径から離すだけです。そのため、円の速度とサイズ、または円の移動方法によっては、奇妙な結果が生じる可能性があります。たとえば、静止している半径 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/

このチュートリアルは4つのパートで構成されており、2Dダイナミクスを非常によく説明しています。

于 2013-03-10T16:18:05.520 に答える
1

2つの円が衝突しているかどうかを確認するより速い方法は、常にそれらの位置を確認することです。実際、それらの中心間の距離がそれらの半径の合計よりも小さいかどうかを確認する必要があります。

一部の「擬似コード」は次のようになります。

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 に答える