private static Boolean RectCirc(CollisionRectangle rectangle, CollisionCircle circle) { // Transform rectangle corner coordinates and circle center to be axis-aligned Matrix rotationMatrix = new Matrix(); rotationMatrix.Set2DRotate(-1 * rectangle.Rotation); Vector rotatedTopLeft = rectangle.TopLeft * rotationMatrix; Vector rotatedTopRight = rectangle.TopRight * rotationMatrix; Vector rotatedBottomLeft = rectangle.BottomLeft * rotationMatrix; Vector rotatedBottomRight = rectangle.BottomRight * rotationMatrix; Vector rotatedCircleCenter = circle.Center * rotationMatrix; double circRadius = circle.Radius; Vector rotatedRectangleCenter = rotatedTopLeft + (rotatedBottomRight - rotatedTopLeft).Multiply(0.5); double rectPercent = rectangle.CollisionPercent; // Use of doubles and matrix operations can cause very very small discrepencies that should be ignored if (Math.Abs(rotatedTopLeft.Y - rotatedTopRight.Y) > 0.00000001) { throw new Exception("Coordinate transform failed in CollisionDetector.RectCirc. TopLeft is " + rotatedTopLeft + " and TopRight is "+ rotatedTopRight); } bool isCircCenterOutsideRect = true; double rectHalfWidth = 0.5 * Math.Abs(rotatedTopRight.X - rotatedTopLeft.X) * rectPercent; double halfWidthPlusRadius = rectHalfWidth + circRadius; double xSeparation = Math.Abs(rotatedCircleCenter.X - rotatedRectangleCenter.X); if (xSeparation >= halfWidthPlusRadius) { return false; } if (xSeparation < rectHalfWidth) { isCircCenterOutsideRect = false; } double rectHalfHeight = 0.5 * Math.Abs(rotatedTopRight.Y - rotatedBottomRight.Y) * rectPercent; double halfHeightPlusRadius = rectHalfWidth + circRadius; double ySeparation = Math.Abs(rotatedCircleCenter.Y - rotatedRectangleCenter.Y); if (ySeparation >= halfHeightPlusRadius) { return false; } if (ySeparation < rectHalfHeight) { isCircCenterOutsideRect = false; } if (!isCircCenterOutsideRect) { return true; } // Check for literal corner cases Vector closestCorner; if (rotatedCircleCenter.X > rotatedRectangleCenter.X && rotatedCircleCenter.Y > rotatedRectangleCenter.Y) { closestCorner = rotatedTopRight; } else if (rotatedCircleCenter.X > rotatedRectangleCenter.X && rotatedCircleCenter.Y <= rotatedRectangleCenter.Y) { closestCorner = rotatedBottomRight; } else if (rotatedCircleCenter.Y > rotatedRectangleCenter.Y) { closestCorner = rotatedTopLeft; } else { closestCorner = rotatedBottomLeft; } if ((closestCorner - rotatedCircleCenter).LengthSquared > circRadius * circRadius) { return false; } return true; }
private static bool IsSeparatingAxis(Vector sepAxisPoint1, Vector sepAxisPoint2, Vector thirdPoint, CollisionRectangle otherRectangle) { Vector[] otherQuadPoints = new Vector[4]; otherQuadPoints[0] = otherRectangle.TopLeft; otherQuadPoints[1] = otherRectangle.TopRight; otherQuadPoints[2] = otherRectangle.BottomLeft; otherQuadPoints[3] = otherRectangle.BottomRight; Vector separatingAxis = sepAxisPoint2 - sepAxisPoint1; Vector normalAxis = new Vector(separatingAxis.Y, -separatingAxis.X); bool referenceSign = normalAxis * (thirdPoint - sepAxisPoint1) >= 0; foreach (Vector cornerOfSecondRect in otherQuadPoints) { bool sign = normalAxis * (cornerOfSecondRect - sepAxisPoint1) >= 0; // A point of the other quad is one the same side as thirdPoint if (sign == referenceSign) { return false; } } // All points of the other quad are on the other side of the edge. Therefore the edge is a separating axis return true; }
private static Boolean RectRect(CollisionRectangle rect1, CollisionRectangle rect2) { double rect1Radius = (rect1.TopLeft - rect1.Center).Length; double rect2Radius = (rect2.TopLeft - rect2.Center).Length; double distanceBetweenCenters = (rect1.Center - rect2.Center).Length; if (distanceBetweenCenters >= rect1Radius + rect2Radius) { return false; } if (IsSeparatingAxis(rect1.TopLeft, rect1.TopRight, rect1.BottomRight, rect2)) { return false; } if (IsSeparatingAxis(rect1.TopRight, rect1.BottomRight, rect1.BottomLeft, rect2)) { return false; } if (IsSeparatingAxis(rect1.BottomRight, rect1.BottomLeft, rect1.TopLeft, rect2)) { return false; } if (IsSeparatingAxis(rect1.BottomLeft, rect1.TopLeft, rect1.TopRight, rect2)) { return false; } if (IsSeparatingAxis(rect2.TopLeft, rect2.TopRight, rect2.BottomRight, rect1)) { return false; } if (IsSeparatingAxis(rect2.TopRight, rect2.BottomRight, rect2.BottomLeft, rect1)) { return false; } if (IsSeparatingAxis(rect2.BottomRight, rect2.BottomLeft, rect2.TopLeft, rect1)) { return false; } if (IsSeparatingAxis(rect2.BottomLeft, rect2.TopLeft, rect2.TopRight, rect1)) { return false; } return true; }