带旋转角度的2D圆形与矩形双向碰撞检测实现求助
圆形与旋转矩形的碰撞检测问题
我正尝试检测圆形与矩形这两类物体的碰撞情况,但始终无法实现该功能。网上多数示例或教程要么数学性过强,要么未考虑矩形的旋转角度。以下是我目前编写的代码及单元测试:
当前实现代码
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") }; } } // 角度单位为弧度 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") }; } }
单元测试代码
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); } }
内容的提问来源于stack exchange,提问作者Marcel
相关产品推荐
相关产品推荐

