Detect 2d collision Circle to Rectangle (with angle) and vice versa

  Kiến thức lập trình

Hi i’m trying to detect when two objects connect , either a circle or rectangle. I can’t figure it out how to do it. Most examples/tutorials online are really math heavy Or doesn’t use the Angle for rectangle

This is what i have so far.

public abstract record Location
{
    public abstract double DistanceTo(Location location);
    public abstract double DirectionTo(Location location);
}

public sealed record CircleLocation(double X, double Y, int Radius) : Location
{
    public override double DistanceTo(Location location)
    {
       return location switch
       {
           CircleLocation circleLocation => Math.Sqrt(Math.Pow(X - circleLocation.X, 2) + Math.Pow(Y - circleLocation.Y, 2)) - circleLocation.Radius,
           RectangleLocation rectangleLocation => Math.Max(rectangleLocation.Left - X, X - rectangleLocation.Right) + Math.Max(rectangleLocation.Top - Y, Y - rectangleLocation.Bottom),
           _ => throw new Exception("Invalid location type")
       };
    }

    public override double DirectionTo(Location location)
    {
        return location switch
        {
            CircleLocation circleLocation => Math.Atan2(circleLocation.Y - Y, circleLocation.X - X),
            RectangleLocation rectangleLocation => Math.Atan2(rectangleLocation.CenterY - Y, rectangleLocation.CenterX - X),
            _ => throw new Exception("Invalid location type")
        };
    }
}

// Angle in radians
public sealed record RectangleLocation(double X, double Y, double Width, double Height, double Angle) : Location
{
    public double Left => X - Math.Cos(Angle) * Width / 2;
    public double Top => Y - Math.Sin(Angle) * Height / 2;
    public double Right => Left + (double)Math.Cos(Angle) * Width;
    public double Bottom => Top + Math.Sin(Angle) * Height;
    public double CenterX => X - Width / 2;
    public double CenterY => Y - Height / 2;

    public override double DistanceTo(Location location)
    {
        return location switch
        {
            CircleLocation circleLocation => Math.Sqrt(Math.Pow(X - circleLocation.X, 2) + Math.Pow(Y - circleLocation.Y, 2)) - circleLocation.Radius,
            RectangleLocation rectangleLocation => Math.Max(rectangleLocation.Left - X, X - rectangleLocation.Right) + Math.Max(rectangleLocation.Top - Y, Y - rectangleLocation.Bottom),
            _ => throw new Exception("Invalid location type")
        };
    }

    public override double DirectionTo(Location location)
    {
        return location switch
        {
            CircleLocation circleLocation => Math.Atan2(circleLocation.Y - Y, circleLocation.X - X),
            RectangleLocation rectangleLocation => Math.Atan2(rectangleLocation.CenterY - CenterY, rectangleLocation.CenterX - CenterX),
            _ => throw new Exception("Invalid location type")
        };
    }
}

Here’s the unit tests i’m playing with

public class UnitTest1
{
    [Fact]
    public void CircleToCircleTouches()
    {
        var circle1 = new CircleLocation(0, 0, 1);
        var circle2 = new CircleLocation(2, 0, 1);

        var distance = circle1.DistanceTo(circle2);

        Assert.Equal(0, distance);
    }

    [Fact]
    public void CircleToCircleDoesNotTouch()
    {
        var circle1 = new CircleLocation(0, 0, 1);
        var circle2 = new CircleLocation(4, 0, 1);

        var distance = circle1.DistanceTo(circle2);

        Assert.Equal(2, distance);
    }

    [Fact]
    public void RectangleToRectangleTouches()
    {
        var rectangle1 = new RectangleLocation(0, 0, 2, 2, 0);
        var rectangle2 = new RectangleLocation(2, 2, 2, 2, 0);

        var distance = rectangle1.DistanceTo(rectangle2);

        Assert.Equal(0, distance);
    }

    [Fact]
    public void RectangleToRectangleDoesNotTouch()
    {
        var rectangle1 = new RectangleLocation(0, 0, 2, 2, 0);
        var rectangle2 = new RectangleLocation(3, 3, 2, 2, 0);

        var distance = rectangle1.DistanceTo(rectangle2);

        Assert.Equal(1, distance);
    }

    [Fact]
    public void TestCircleToRectangleDistance()
    {
        var circle = new CircleLocation(0, 0, 1);
        var rectangle = new RectangleLocation(3, 4, 2, 2, 0);

        var distance = circle.DistanceTo(rectangle);

        Assert.Equal(5, distance);
    }

    [Fact]
    public void TestRectangleToCircleDistance()
    {
        var rectangle = new RectangleLocation(0, 0, 2, 2, 0);
        var circle = new CircleLocation(3, 4, 1);

        var distance = rectangle.DistanceTo(circle);

        Assert.Equal(5, distance, 1);
    }
}

LEAVE A COMMENT