1

Just made a little theory to simplify my problem.. I want to know if it's possible or easier way to do this.

I'm making a game simulation in C# where robots play soccer with AI. But need to prevent them from walking in eachother, find the exact point of impact to update their position so they can't walk into eachother.

Thanks.

This is not a duplicate since I was asking another theory I was working out.

Circle Collision Theory

Jesse
  • 544
  • 5
  • 24

3 Answers3

2

Well, from the answer I already provided from your previous question, is there anything you don't understand or need help with? It does pretty much exactly what you're asking here (so "yes, you can employ polar coordinates like this.")

However, your comment about the "last known position where they didn't collide" would mean you would have to track their positions and maintain their last good state and revert to it. Not sure if that's necessary in this case or if you would rather just calculate a new "best-fit" location.


Well, you already marked an answer, but I went and put together a fully functioning piece of code, so maybe you can use it anyway. :) From my comment:

Since they're just circles, just calculate the midpoint between the circles' centre points. If the circles have different radii, choose one circle and calculate the point along the line one radius away from its centre.

This might be a simple implementation. I created some very meager helper classes for it; I would totally encourage extending them, making the structs truly immutable, and all that good jazz, but for now serve okay for demonstration purposes.

So for helper classes:

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

Our meat-and-potatoes class/method is this:

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

Usage might look like:

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

Outputs:

Did not collide.
Collision detected at (1.5, 4)! Safe location for circle 1: (0.158359213500125, 1.31671842700025), circle 2: (3.73606797749979, 8.47213595499958)

I don't know if it's necessary in your case to deal with the complexity of calculating true intersections of two circles (where they would intersect at two points) and such. Likely something along these lines would be sufficient for you. I definitely encourage healthy unit tests and making the classes proper beyond what I have here. :)

Significantly in this case, and this would depend on what you want to do with it for your application, is that when the circles overlap, it simply calculates the midpoint between them then moves each circle away from that midpoint their respective radii. So depending on the speed and size of the circles, or how they are moving, it might produce weird results. For example, if you had a big 10 radius circle sitting still, then you throw in a 1 radius circle only 0.5 distance from the big circle's centre, that big circle is going to shift about 9.75 units! If you don't get into big overlapping conditions, then maybe it's not much of an issue. I think at the very least this will give you some information about the collision and then how you want your circles to react as a result will be up to you.

Community
  • 1
  • 1
Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93
1

Might be this is helpful for you: http://www.emanueleferonato.com/2011/06/13/slicing-splitting-and-cutting-objects-with-box2d/

This tutorial consist of four parts and explain the 2D dynamics very well.

Shaharyar
  • 12,254
  • 4
  • 46
  • 66
  • Didn't need a raycast.. but well it's very helpful as I was designing a raycast method in my engine. – Jesse Mar 10 '13 at 16:28
1

The faster way to see if the two circles are colliding is to constantly check their positions. Infact you have to check if the distance between their centers is smaller than the sum of their radius.

Some "pseudo code" could be:

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: Note that I didn't use Math.Pow() due to its performance.

Omar
  • 16,329
  • 10
  • 48
  • 66
  • That is just a simple collision detection. Look closely to my questions. It's rather complicated than this. I need to know the exact point of impact ;) – Jesse Mar 10 '13 at 16:52
  • 1
    The exact point of collision is `collisionX` and `collisionY`. – Omar Mar 10 '13 at 17:06
  • circle1.X is the midpoint of the circle. Not a definition of a point on the circle. – Jesse Mar 10 '13 at 17:11
  • Yes, it is used to detect the collision and find the point of the collision. – Omar Mar 10 '13 at 17:22
  • 1
    Sorry. Now I see it. Was on my phone. Many thanks sir :) – Jesse Mar 10 '13 at 22:39