public void Move(List <IPolygon> polygons, Vector2 velocity) { Vector2 translation = velocity; foreach (Polygon polygon in polygons) { CollisionResult result = Simulate(polygon, velocity); if (result.WillIntersect && this.IsTangible && polygon.IsTangible) { translation += result.MinimumTranslation; //break; } if (result.AreIntersecting) { this.OnCollide?.Invoke(this, polygon); polygon.OnCollide?.Invoke(polygon, this); } } Position += translation; }
/// <summary> /// Simulate collision between this polygon and another <paramref name="polygon"/> with <paramref name="velocity"/> /// </summary> /// <param name="polygon"></param> /// <param name="velocity"></param> /// <returns></returns> public CollisionResult Simulate(IPolygon polygon, Vector2 velocity) { CollisionResult result = new CollisionResult(); result.AreIntersecting = true; result.WillIntersect = true; int edgeCountA = this.Edges.Count; int edgeCountB = polygon.Edges.Count; float minimumInterval = float.PositiveInfinity; Vector2 translationAxis = Vector2.Zero; Vector2 edge = Vector2.Zero; // loop through edges of both polygons for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) { if (edgeIndex < edgeCountA) { edge = this.Edges[edgeIndex]; } else { edge = polygon.Edges[edgeIndex - edgeCountA]; } // find if the polygons are intersecting. // find the axis perpendicular to the current edge Vector2 axis = new Vector2(-edge.Y, edge.X); axis.Normalize(); // find the projection of the axis float minA = 0, minB = 0, maxA = 0, maxB = 0; projectPolygon(axis, this, ref minA, ref maxA); projectPolygon(axis, polygon, ref minB, ref maxB); // check if projections are intersecting if (intervalDistance(minA, maxA, minB, maxB) > 0) { result.AreIntersecting = false; } // find if polygons _will_ intersect float velocityProjection = Vector2.Dot(axis, velocity); // get the projection of this poly during movement if (velocityProjection < 0) { minA += velocityProjection; } else { maxA += velocityProjection; } // same test for new projection float interval = intervalDistance(minA, maxA, minB, maxB); if (interval > 0) { result.WillIntersect = false; } if (!result.AreIntersecting && !result.WillIntersect) { break; } // check if the current interval is the minimum one interval = Math.Abs(interval); if (interval < minimumInterval) { minimumInterval = interval; translationAxis = axis; Vector2 d = this.Center - polygon.Center; if (Vector2.Dot(d, translationAxis) < 0) { translationAxis = -translationAxis; } } } if (result.WillIntersect) { result.MinimumTranslation = translationAxis * minimumInterval; } return(result); }