public Polygon(Polygon p) { foreach (Vector2 point in p.Points) { m_Points.Add(point); } BuildEdges(); CalculateMaxMin(); }
/// <summary> /// The default Constructor. /// </summary> public Camera(float prefWidth, float prefHeight, float windowWidth, float windowHeight, MouseDevice m) { OriginalBounds = CameraBounds = new Polygon(); TargetScale = Scale = new Vector2(1f, 1f); MinimumScale = new Vector2(0.5f, 0.5f); MaximumScale = new Vector2(20, 20); CameraBox = new Polygon(); Mouse = m; PreferredWidth = prefWidth; PreferredHeight = prefHeight; UpdateResize(windowWidth, windowHeight); UpdateProjectionMatrix(); }
// Calculate the projection of a polygon on an axis and returns it as a [min, max] interval public 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 d = Vector2.Dot(axis, polygon.Points[0]); min = d; max = d; foreach (Vector2 t in polygon.Points) { d = Vector2.Dot(t, axis); if (d < min) { min = d; } else { if (d > max) { max = d; } } } }
// Structure that stores the results of the PolygonCollision function // Check if polygon A is going to collide with polygon B for the given velocity public static PolygonCollisionResult PolygonCollision(Polygon polygonA, Polygon polygonB, Vector2 velocity) { var result = new PolygonCollisionResult {Intersect = true, WillIntersect = true}; int edgeCountA = polygonA.Edges.Count; int edgeCountB = polygonB.Edges.Count; float minIntervalDistance = float.PositiveInfinity; var translationAxis = new Vector2(); Vector2 edge; // Loop through all the edges of both polygons for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) { edge = edgeIndex < edgeCountA ? polygonA.Edges[edgeIndex] : polygonB.Edges[edgeIndex - edgeCountA]; // ===== 1. Find if the polygons are currently intersecting ===== // Find the axis perpendicular to the current edge var axis = new Vector2(-edge.Y, edge.X); axis.Normalize(); // Find the projection of the polygon on the current axis float minA = 0; float minB = 0; float maxA = 0; float maxB = 0; ProjectPolygon(axis, polygonA, ref minA, ref maxA); ProjectPolygon(axis, polygonB, ref minB, ref maxB); // Check if the polygon projections are currentlty intersecting if (IntervalDistance(minA, maxA, minB, maxB) > 0) result.Intersect = false; // ===== 2. Now find if the polygons *will* intersect ===== // Project the velocity on the current axis float velocityProjection = Vector2.Dot(axis, velocity); // Get the projection of polygon A during the movement if (velocityProjection < 0) { minA += velocityProjection; } else { maxA += velocityProjection; } // Do the same test as above for the new projection float intervalDistance = IntervalDistance(minA, maxA, minB, maxB); if (intervalDistance > 0) result.WillIntersect = false; // If the polygons are not intersecting and won't intersect, exit the loop if (!result.Intersect && !result.WillIntersect) 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 = System.Math.Abs(intervalDistance); if (intervalDistance < minIntervalDistance) { minIntervalDistance = intervalDistance; translationAxis = axis; Vector2 d = polygonA.Center - polygonB.Center; if (Vector2.Dot(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; result.IntervalDistance = minIntervalDistance; return result; }
public static PolygonCollisionResult PolygonCollision(Polygon polygonA, Polygon polygonB) { return PolygonCollision(polygonA, polygonB, Vector2.Zero); }
public bool IsIntersecting(Polygon p) { PolygonCollisionResult polygonCollisionResult = PolygonCollision(this, p); return polygonCollisionResult.Intersect; }
private void ClampTranslations() { GenerateCameraBoundingBox(); var bbox = new Polygon(CameraBox); bbox.Scale(TargetScale); bbox.BuildEdges(); bbox.CalculateMaxMin(); if (bbox.Width > CameraBounds.Width && CameraBounds.Width >= CameraBounds.Height) { TargetScale.X = CameraBounds.Width/(PreferredWidth); } if (bbox.Height > CameraBounds.Height && CameraBounds.Height >= CameraBounds.Width) { TargetScale.Y = CameraBounds.Height/(PreferredHeight); } if (TargetScale.Y > TargetScale.X) { TargetScale.Y = TargetScale.X; } else if (TargetScale.X > TargetScale.Y) { TargetScale.X = TargetScale.Y; } CameraBox.Scale(Scale); CameraBox.BuildEdges(); CameraBox.CalculateMaxMin(); //Clamp translation values if (CameraBox.Max.X > CameraBounds.Max.X) { TargetWorldTranslation.X += ((CameraBox.Max.X) - CameraBounds.Max.X); } else if (CameraBox.Min.X < CameraBounds.Min.X) { TargetWorldTranslation.X += ((CameraBox.Min.X) - CameraBounds.Min.X); } //Clamp translation values if (CameraBox.Max.Y > CameraBounds.Max.Y) { TargetWorldTranslation.Y += (CameraBox.Max.Y - CameraBounds.Max.Y); } else if (CameraBox.Min.Y < CameraBounds.Min.Y) { TargetWorldTranslation.Y += (CameraBox.Min.Y - CameraBounds.Min.Y); } }