1

ロボットが AI でサッカーをするロボカップに関する学校のプロジェクトを行っています。すべてがうまくいくので、私はまだ何かに行き詰まっています。

ロボットは、上から見た単純な球体です。両方のプレーヤーが互いに歩み寄ってはならず、インパクトのポイントで新しい更新された位置を取得する必要があります。

衝突ハンドラーは、衝突するかどうかをチェックするだけなので、円が衝突する場所を検出する方法があるかどうかを期待していました。したがって、衝突する球体の位置を、衝突していないことがわかっている最後の位置に更新して、球体が互いに通り抜けて跳ね返ることがないようにすることができます。

4

3 に答える 3

2

円の円周上のすべての点は、円の中心から同じ距離 (半径) にあります。これは競技場のすべてのサークルに当てはまります。

したがって、2 つの円は、中心間の距離がそれぞれの半径の合計以下である場合に正確に衝突しています。

于 2013-03-08T23:15:22.230 に答える
1

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

それらは単なる円なので、円の中心点の間の中点を計算するだけです. 円の半径が異なる場合は、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点で交差する場所)などを計算する複雑さに対処する必要があるかどうかはわかりません。これらの線に沿ったもので十分でしょう。私は間違いなく健全な単体テストを奨励し、ここにあるものを超えて適切なクラスを作成します。:)

EDIT:この場合、重要なことは、アプリケーションで何をしたいかによって異なりますが、円が重なっている場合、それらの間の中点を計算し、各円をその中点からそれぞれの半径移動するだけです。そのため、円の速度とサイズ、または円の移動方法によっては、奇妙な結果が生じる可能性があります。たとえば、静止している半径 10 の大きな円がある場合、大きな円の中心からわずか 0.5 の距離に半径 1 の円を投げると、その大きな円は約 9.75 単位シフトします! 大きな重複条件に陥らない場合は、あまり問題にならないかもしれません。少なくとも、これで衝突に関する情報が得られると思います。結果はあなた次第になるので、あなたのサークルが反応することを望みます。

于 2013-03-08T23:56:41.073 に答える
0

あなたがする必要があるのは、2 つの円の交点を見つけることです。これは、2 つの点、1 つの点、またはまったくない可能性があります。これは基本的に、2 つの円の方程式を一緒に解くことによって行われます。数学は次のとおりです。

http://www.analyzemath.com/CircleEq/circle_intersection.html

これは学校用なので、コーディングはあなたに任せます:)

于 2013-03-08T23:15:47.377 に答える