public static PolygonCollisionResult PolygonCollisionResult(Polygon polygonMoving, Polygon polygon, Vector2 velocity) { PolygonCollisionResult result = new PolygonCollisionResult(); float minIntervalDistance = float.PositiveInfinity; Vector2 translationAxis = Vector2.Zero; List<Vector2> edges = new List<Vector2>(polygonMoving.Edges); edges.AddRange(polygon.Edges); foreach (Vector2 edge in edges) { // Find the axis perpendicular to the current edge Vector2 axis = new Vector2(-edge.Y, edge.X); axis.Normalize(); // Find the projection of the polygon on the current axis float minPolygonMoving = 0; float maxPolygonMoving = 0; float minPolygon = 0; float maxPolygon = 0; ProjectPolygon(axis, polygonMoving, ref minPolygonMoving, ref maxPolygonMoving); ProjectPolygon(axis, polygon, ref minPolygon, ref maxPolygon); // Project the velocity on the current axis float velocityProjection = VectorUtil.DotProduct(axis, velocity); // Get the projection of polygon A during the movement if (velocityProjection < 0) { minPolygonMoving += velocityProjection; } else { maxPolygonMoving += velocityProjection; } // Do the same test as above for the new projection float intervalDistance = IntervalDistance(minPolygonMoving, maxPolygonMoving, minPolygon, maxPolygon); if (intervalDistance > 0) { result.WillIntersect = false; break; } // Check if the current interval distance is the minimum one. If so store // the interval distance and the current distance. // This will be used to calculate the minimum translation vector intervalDistance = Math.Abs(intervalDistance); if (intervalDistance < minIntervalDistance) { minIntervalDistance = intervalDistance; translationAxis = axis; Vector2 d = polygonMoving.Center - polygon.Center; if (VectorUtil.DotProduct(d, translationAxis) < 0) translationAxis = -translationAxis; } } // The minimum translation vector can be used to push the polygons appart. // First moves the polygons by their velocity // then move polygonA by MinimumTranslationVector. if (result.WillIntersect) result.MinimumTranslationVector = translationAxis * minIntervalDistance; return result; }
// Calculate the projection of a polygon on an axis and returns it as a [min, max] interval private static void ProjectPolygon(Vector2 axis, Polygon polygon, ref float min, ref float max) { // To project a point on an axis use the dot product float temp = VectorUtil.DotProduct(axis, polygon.Points[0]); min = temp; max = temp; for (int i = 0; i < polygon.Points.Count; i++) { temp = VectorUtil.DotProduct(polygon.Points[i], axis); if (temp < min) { min = temp; } else { if (temp > max) { max = temp; } } } }