/// <summary> /// Returns whether this instance collides with the argument AxisAlignedRectangle. /// </summary> /// <param name="rectangle">The AxisAlignedRectangle to test collision against.</param> /// <returns>Whether a collision has occurred.</returns> #endregion public bool CollideAgainst(AxisAlignedRectangle rectangle) { UpdateDependencies(TimeManager.CurrentTime); rectangle.UpdateDependencies(TimeManager.CurrentTime); // Get world-positioned segment Segment a = AsSegment(); // Check if one of the segment's endpoints is inside the rectangle Vector3 endpoint = new Vector3( (float)a.Point1.X, (float)a.Point1.Y, 0f); if (rectangle.IsPointInside(ref endpoint)) { mLastCollisionPoint = new Point(ref endpoint); return(true); } endpoint = new Vector3( (float)a.Point2.X, (float)a.Point2.Y, 0f); if (rectangle.IsPointInside(ref endpoint)) { mLastCollisionPoint = new Point(ref endpoint); return(true); } // Check if the segment intersects any of the rectangle's edges // Here, prepare rectangle's corner points Point tl = new Point( rectangle.Position.X - rectangle.ScaleX, rectangle.Position.Y + rectangle.ScaleY); Point tr = new Point( rectangle.Position.X + rectangle.ScaleX, rectangle.Position.Y + rectangle.ScaleY); Point bl = new Point( rectangle.Position.X - rectangle.ScaleX, rectangle.Position.Y - rectangle.ScaleY); Point br = new Point( rectangle.Position.X + rectangle.ScaleX, rectangle.Position.Y - rectangle.ScaleY); Point tempPoint; // Test if any of the edges intersect the segment // (this will short-circuit on the first true test) if (a.Intersects(new Segment(tl, tr), out tempPoint) || a.Intersects(new Segment(tl, bl), out tempPoint) || a.Intersects(new Segment(bl, br), out tempPoint) || a.Intersects(new Segment(tr, br), out tempPoint)) { mLastCollisionPoint = tempPoint; return(true); } // No collision return(false); }
/// <summary> /// Returns whether this instance collides with the argument Polygon. /// </summary> /// <param name="polygon">The Polygon to test collision against.</param> /// <returns>Whether a collision has occurred.</returns> #endregion public bool CollideAgainst(Polygon polygon) { UpdateDependencies(TimeManager.CurrentTime); polygon.UpdateDependencies(TimeManager.CurrentTime); Point transformedPoint1 = new Point(RelativePoint1.X, RelativePoint1.Y); Point transformedPoint2 = new Point(RelativePoint2.X, RelativePoint2.Y); FlatRedBall.Math.MathFunctions.TransformPoint(ref transformedPoint1, ref mRotationMatrix); FlatRedBall.Math.MathFunctions.TransformPoint(ref transformedPoint2, ref mRotationMatrix); Point tp1 = new Point(transformedPoint1.X, transformedPoint1.Y); Point tp2 = new Point(transformedPoint2.X, transformedPoint2.Y); // Get world-positioned segment Segment a = new Segment( new Point(Position.X + transformedPoint1.X, Position.Y + transformedPoint1.Y), new Point(Position.X + transformedPoint2.X, Position.Y + transformedPoint2.Y)); // Check if one of the segment's endpoints is inside the Polygon if (polygon.IsPointInside(ref tp1, ref Position, ref mIdentityMatrix)) { polygon.mLastCollisionPoint = tp1; mLastCollisionPoint = tp1; return(true); } if (polygon.IsPointInside(ref tp2, ref Position, ref mIdentityMatrix)) { polygon.mLastCollisionPoint = tp2; mLastCollisionPoint = tp2; return(true); } Point intersectionPoint; // Check if one of the polygon's edges intersects the line segment for (int i = 0; i < polygon.Points.Count - 1; i++) { int indexAfter = i + 1; var point1 = new Point(polygon.Vertices[i].Position.X, polygon.Vertices[i].Position.Y); var point2 = new Point(polygon.Vertices[indexAfter].Position.X, polygon.Vertices[indexAfter].Position.Y); if (a.Intersects(new Segment(point1, point2), out intersectionPoint)) { mLastCollisionPoint = intersectionPoint; polygon.mLastCollisionPoint = intersectionPoint; return(true); } } // No collision return(false); }
/// <summary> /// Returns whether this instance collides with the argument Line. /// </summary> /// <param name="line">The Line to test collision against.</param> /// <returns>Whether a collision has occurred.</returns> #endregion public bool CollideAgainst(Line line) { UpdateDependencies(TimeManager.CurrentTime); line.UpdateDependencies(TimeManager.CurrentTime); // Get world-positioned segment Segment a = AsSegment(); // Get world-positioned segment Segment b = line.AsSegment(); // Perform the intersection test bool result = a.Intersects(b, out mLastCollisionPoint); line.mLastCollisionPoint = mLastCollisionPoint; return(result); }
public float DistanceTo(Segment otherSegment) { if (otherSegment.Intersects(this)) { return(0); } else { float minDistance = float.PositiveInfinity; minDistance = System.Math.Min(minDistance, this.DistanceTo(otherSegment.Point1)); minDistance = System.Math.Min(minDistance, this.DistanceTo(otherSegment.Point2)); minDistance = System.Math.Min(minDistance, otherSegment.DistanceTo(this.Point1)); minDistance = System.Math.Min(minDistance, otherSegment.DistanceTo(this.Point2)); return(minDistance); } }
public bool Intersects(Segment segment, out Point intersectionPoint) { Segment top = new Segment(this.Left, this.Top, this.Right, this.Top); Segment bottom = new Segment(this.Left, this.Bottom, this.Right, this.Bottom); Segment left = new Segment(this.Left, this.Top, this.Left, this.Bottom); Segment right = new Segment(this.Right, this.Top, this.Right, this.Bottom); intersectionPoint = new Point(); Point tempPoint = new Point(); if (top.Intersects(segment, out tempPoint)) { intersectionPoint = tempPoint; return(true); } if (bottom.Intersects(segment, out tempPoint)) { intersectionPoint = tempPoint; return(true); } if (left.Intersects(segment, out tempPoint)) { intersectionPoint = tempPoint; return(true); } if (right.Intersects(segment, out tempPoint)) { intersectionPoint = tempPoint; return(true); } return(false); }
private static List<ContactPoint> GetContactPoints(Segment[] firstSegments, Segment[] secondSegments) { if (shouldEliminatePointOnEnd) { ShiftEndpointsToEliminatePointOnSegment(firstSegments, secondSegments); } Point intersectionPoint = new Point(); List<ContactPoint> contactPoints = new List<ContactPoint>(); Segment firstSegment = new Segment(); Segment secondSegment = new Segment(); const double allowedError = .0005; bool debug = false; #if !SILVERLIGHT && !MONOGAME && !XBOX360 && !WINDOWS_PHONE if (debug) { FlatRedBall.Content.Polygon.PolygonSaveList psl = new FlatRedBall.Content.Polygon.PolygonSaveList(); psl.PolygonSaves.Add( FlatRedBall.Content.Polygon.PolygonSave.FromPolygon( Polygon.FromSegments(firstSegments))); psl.PolygonSaves.Add( FlatRedBall.Content.Polygon.PolygonSave.FromPolygon( Polygon.FromSegments(secondSegments))); psl.Save(FlatRedBall.IO.FileManager.MyDocuments + "modifiedPolygons.plylstx"); } #endif #region Handle the two-parallel segment special case List<ContactPoint> parallelContactPoints = new List<ContactPoint>(); for (int firstIndex = 0; firstIndex < firstSegments.Length; firstIndex++) { firstSegment = firstSegments[firstIndex]; for (int secondIndex = 0; secondIndex < secondSegments.Length; secondIndex++) { secondSegment = secondSegments[secondIndex]; Point parallelIntersectionPoint; if (firstSegment.IsParallelAndTouching(secondSegment, out parallelIntersectionPoint)) { ContactPoint cp = new ContactPoint(); cp.ThisIndex = firstIndex; cp.OtherIndex = secondIndex; // Technically this is a point on segment intersection, // but we treat it like a segment intersection because we're // going to eliminate duplicates cp.ContactType = ContactType.SegmentIntersection; cp.Position = new Vector3((float)parallelIntersectionPoint.X, (float)parallelIntersectionPoint.Y, 0); parallelContactPoints.Add(cp); } } } #endregion #region else, do regular intersection tests List<int> indexesToRemove = new List<int>(); for (int firstSegmentIndex = 0; firstSegmentIndex < firstSegments.Length; firstSegmentIndex++) { firstSegment = firstSegments[firstSegmentIndex]; for (int secondSegmentIndex = 0; secondSegmentIndex < secondSegments.Length; secondSegmentIndex++) { secondSegment = secondSegments[secondSegmentIndex]; bool intersects = firstSegment.Intersects(secondSegment, out intersectionPoint); if ( intersects || firstSegment.IsParallelAndTouching(secondSegment, out intersectionPoint)) { ContactPoint cp = new ContactPoint(); cp.Position = new Vector3((float)intersectionPoint.X, (float)intersectionPoint.Y, 0); cp.ThisIndex = firstSegmentIndex; cp.OtherIndex = secondSegmentIndex; cp.ThisEndpoint = -1; cp.OtherEndpoint = -1; if(intersectionPoint.EqualdWithin(firstSegment.Point1, allowedError)) { cp.ThisEndpoint = firstSegmentIndex; } else if(intersectionPoint.EqualdWithin(firstSegment.Point2, allowedError)) { cp.ThisEndpoint = firstSegmentIndex + 1; } else if(intersectionPoint.EqualdWithin(secondSegment.Point1, allowedError)) { cp.OtherEndpoint = secondSegmentIndex; } else if(intersectionPoint.EqualdWithin(secondSegment.Point2, allowedError)) { cp.OtherEndpoint = secondSegmentIndex + 1; } if (!intersects || cp.ThisEndpoint != -1 || cp.OtherEndpoint != -1 ) { if (shouldEliminatePointOnEnd) { throw new Exception(); } cp.ContactType = ContactType.PointOnSegment; } else { cp.ContactType = ContactType.SegmentIntersection; } if (!intersects) { indexesToRemove.Add(contactPoints.Count); } contactPoints.Add(cp); } } } #if false // Not sure why this is here, but it causes warnings and we don't use it if (false && parallelContactPoints.Count == 2) { const float minimumLength = .01f; bool isParallelContactPoint = false; for (int i = 0; i < contactPoints.Count; i++) { float closestToPair = float.PositiveInfinity; Vector3 position = contactPoints[i].Position; for (int parallelIndex = 0; parallelIndex < parallelContactPoints.Count; parallelIndex++) { Segment segment1 = firstSegments[parallelContactPoints[parallelIndex].ThisIndex]; Segment segment2 = secondSegments[parallelContactPoints[parallelIndex].OtherIndex]; float firstDistance = segment1.DistanceTo(position.X, position.Y); float secondDistance = segment2.DistanceTo(position.X, position.Y); float furthestAway = System.Math.Max(firstDistance, secondDistance); closestToPair = System.Math.Min(furthestAway, closestToPair); } if (closestToPair > minimumLength) { isParallelContactPoint = true; break; } } if (!isParallelContactPoint) { return parallelContactPoints; } } #endif int numberKilled = 0; List<int> intersectionIndexes = new List<int>(); for (int i = 0; i < firstSegments.Length; i++) { intersectionIndexes.Clear(); for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++) { if (contactPoints[cpIndex].ThisIndex == i) { intersectionIndexes.Add(cpIndex); } } if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1) { contactPoints.RemoveAt(intersectionIndexes[1]); } } for (int i = 0; i < secondSegments.Length; i++) { intersectionIndexes.Clear(); for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++) { if (contactPoints[cpIndex].OtherIndex == i) { intersectionIndexes.Add(cpIndex); } } if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1) { contactPoints.RemoveAt(intersectionIndexes[1]); } } // See if any contact points are the same. If so, kill them for (int firstCP = 0; firstCP < contactPoints.Count - 1; firstCP++) { for (int secondCP = 1; secondCP < contactPoints.Count; secondCP++) { if (firstCP == secondCP) { continue; } float distanceApart = (contactPoints[firstCP].Position - contactPoints[secondCP].Position).Length(); if (distanceApart < .002) { contactPoints.RemoveAt(secondCP); firstCP = -1; // start over. numberKilled++; break; } } } if (contactPoints.Count == 1) { // Is this bad? What do we do? //int m = 3; } if (contactPoints.Count % 2 != 0 && contactPoints.Count > 1) { // Oh, no, an odd number of contact points? Let's kill the closest pair ReactToOddContactPointCount(contactPoints); } #endregion return contactPoints; }
public float DistanceTo(Segment otherSegment) { if (otherSegment.Intersects(this)) { return 0; } else { float minDistance = float.PositiveInfinity; minDistance = System.Math.Min(minDistance, this.DistanceTo(otherSegment.Point1)); minDistance = System.Math.Min(minDistance, this.DistanceTo(otherSegment.Point2)); minDistance = System.Math.Min(minDistance, otherSegment.DistanceTo(this.Point1)); minDistance = System.Math.Min(minDistance, otherSegment.DistanceTo(this.Point2)); return minDistance; } }
private static List <ContactPoint> GetContactPoints(Segment[] firstSegments, Segment[] secondSegments) { if (shouldEliminatePointOnEnd) { ShiftEndpointsToEliminatePointOnSegment(firstSegments, secondSegments); } Point intersectionPoint = new Point(); List <ContactPoint> contactPoints = new List <ContactPoint>(); Segment firstSegment = new Segment(); Segment secondSegment = new Segment(); const double allowedError = .0005; bool debug = false; #if !SILVERLIGHT && !MONOGAME && !XBOX360 && !WINDOWS_PHONE if (debug) { FlatRedBall.Content.Polygon.PolygonSaveList psl = new FlatRedBall.Content.Polygon.PolygonSaveList(); psl.PolygonSaves.Add( FlatRedBall.Content.Polygon.PolygonSave.FromPolygon( Polygon.FromSegments(firstSegments))); psl.PolygonSaves.Add( FlatRedBall.Content.Polygon.PolygonSave.FromPolygon( Polygon.FromSegments(secondSegments))); psl.Save(FlatRedBall.IO.FileManager.MyDocuments + "modifiedPolygons.plylstx"); } #endif #region Handle the two-parallel segment special case List <ContactPoint> parallelContactPoints = new List <ContactPoint>(); for (int firstIndex = 0; firstIndex < firstSegments.Length; firstIndex++) { firstSegment = firstSegments[firstIndex]; for (int secondIndex = 0; secondIndex < secondSegments.Length; secondIndex++) { secondSegment = secondSegments[secondIndex]; Point parallelIntersectionPoint; if (firstSegment.IsParallelAndTouching(secondSegment, out parallelIntersectionPoint)) { ContactPoint cp = new ContactPoint(); cp.ThisIndex = firstIndex; cp.OtherIndex = secondIndex; // Technically this is a point on segment intersection, // but we treat it like a segment intersection because we're // going to eliminate duplicates cp.ContactType = ContactType.SegmentIntersection; cp.Position = new Vector3((float)parallelIntersectionPoint.X, (float)parallelIntersectionPoint.Y, 0); parallelContactPoints.Add(cp); } } } #endregion #region else, do regular intersection tests List <int> indexesToRemove = new List <int>(); for (int firstSegmentIndex = 0; firstSegmentIndex < firstSegments.Length; firstSegmentIndex++) { firstSegment = firstSegments[firstSegmentIndex]; for (int secondSegmentIndex = 0; secondSegmentIndex < secondSegments.Length; secondSegmentIndex++) { secondSegment = secondSegments[secondSegmentIndex]; bool intersects = firstSegment.Intersects(secondSegment, out intersectionPoint); if (intersects || firstSegment.IsParallelAndTouching(secondSegment, out intersectionPoint)) { ContactPoint cp = new ContactPoint(); cp.Position = new Vector3((float)intersectionPoint.X, (float)intersectionPoint.Y, 0); cp.ThisIndex = firstSegmentIndex; cp.OtherIndex = secondSegmentIndex; cp.ThisEndpoint = -1; cp.OtherEndpoint = -1; if (intersectionPoint.EqualdWithin(firstSegment.Point1, allowedError)) { cp.ThisEndpoint = firstSegmentIndex; } else if (intersectionPoint.EqualdWithin(firstSegment.Point2, allowedError)) { cp.ThisEndpoint = firstSegmentIndex + 1; } else if (intersectionPoint.EqualdWithin(secondSegment.Point1, allowedError)) { cp.OtherEndpoint = secondSegmentIndex; } else if (intersectionPoint.EqualdWithin(secondSegment.Point2, allowedError)) { cp.OtherEndpoint = secondSegmentIndex + 1; } if (!intersects || cp.ThisEndpoint != -1 || cp.OtherEndpoint != -1 ) { if (shouldEliminatePointOnEnd) { throw new Exception(); } cp.ContactType = ContactType.PointOnSegment; } else { cp.ContactType = ContactType.SegmentIntersection; } if (!intersects) { indexesToRemove.Add(contactPoints.Count); } contactPoints.Add(cp); } } } #if false // Not sure why this is here, but it causes warnings and we don't use it if (false && parallelContactPoints.Count == 2) { const float minimumLength = .01f; bool isParallelContactPoint = false; for (int i = 0; i < contactPoints.Count; i++) { float closestToPair = float.PositiveInfinity; Vector3 position = contactPoints[i].Position; for (int parallelIndex = 0; parallelIndex < parallelContactPoints.Count; parallelIndex++) { Segment segment1 = firstSegments[parallelContactPoints[parallelIndex].ThisIndex]; Segment segment2 = secondSegments[parallelContactPoints[parallelIndex].OtherIndex]; float firstDistance = segment1.DistanceTo(position.X, position.Y); float secondDistance = segment2.DistanceTo(position.X, position.Y); float furthestAway = System.Math.Max(firstDistance, secondDistance); closestToPair = System.Math.Min(furthestAway, closestToPair); } if (closestToPair > minimumLength) { isParallelContactPoint = true; break; } } if (!isParallelContactPoint) { return(parallelContactPoints); } } #endif int numberKilled = 0; List <int> intersectionIndexes = new List <int>(); for (int i = 0; i < firstSegments.Length; i++) { intersectionIndexes.Clear(); for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++) { if (contactPoints[cpIndex].ThisIndex == i) { intersectionIndexes.Add(cpIndex); } } if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1) { contactPoints.RemoveAt(intersectionIndexes[1]); } } for (int i = 0; i < secondSegments.Length; i++) { intersectionIndexes.Clear(); for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++) { if (contactPoints[cpIndex].OtherIndex == i) { intersectionIndexes.Add(cpIndex); } } if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1) { contactPoints.RemoveAt(intersectionIndexes[1]); } } // See if any contact points are the same. If so, kill them for (int firstCP = 0; firstCP < contactPoints.Count - 1; firstCP++) { for (int secondCP = 1; secondCP < contactPoints.Count; secondCP++) { if (firstCP == secondCP) { continue; } float distanceApart = (contactPoints[firstCP].Position - contactPoints[secondCP].Position).Length(); if (distanceApart < .002) { contactPoints.RemoveAt(secondCP); firstCP = -1; // start over. numberKilled++; break; } } } if (contactPoints.Count == 1) { // Is this bad? What do we do? //int m = 3; } if (contactPoints.Count % 2 != 0 && contactPoints.Count > 1) { // Oh, no, an odd number of contact points? Let's kill the closest pair ReactToOddContactPointCount(contactPoints); } #endregion return(contactPoints); }
public bool CollideAgainst(Capsule2D otherCapsule) { this.UpdateDependencies(TimeManager.CurrentTime); otherCapsule.UpdateDependencies(TimeManager.CurrentTime); #region Create some initial variables which will be used below Vector3 thisEndpoint1 = this.Endpoint1Position; Vector3 thisEndpoint2 = this.Endpoint2Position; Vector3 otherEndpoint1 = otherCapsule.Endpoint1Position; Vector3 otherEndpoint2 = otherCapsule.Endpoint2Position; #endregion #region Point vs. Point (circle collision) float radiiCombinedSquared = (mEndpointRadius + otherCapsule.mEndpointRadius) * (mEndpointRadius + otherCapsule.mEndpointRadius); Vector3 difference1 = thisEndpoint1 - otherEndpoint1; Vector3 difference2 = thisEndpoint1 - otherEndpoint2; Vector3 difference3 = thisEndpoint2 - otherEndpoint1; Vector3 difference4 = thisEndpoint2 - otherEndpoint2; if ( #if FRB_MDX difference1.LengthSq() < radiiCombinedSquared || difference2.LengthSq() < radiiCombinedSquared || difference3.LengthSq() < radiiCombinedSquared || difference4.LengthSq() < radiiCombinedSquared) #else //if FRB_XNA || SILVERLIGHT || WINDOWS_PHONE difference1.LengthSquared() < radiiCombinedSquared || difference2.LengthSquared() < radiiCombinedSquared || difference3.LengthSquared() < radiiCombinedSquared || difference4.LengthSquared() < radiiCombinedSquared) #endif { return(true); } #endregion #region Segment vs. Segment (bandaid collision) Segment thisTopSegment = this.TopSegment; Segment thisBottomSegment = this.BottomSegment; Segment otherTopSegment = otherCapsule.TopSegment; Segment otherBottomSegment = otherCapsule.BottomSegment; if ( thisTopSegment.Intersects(otherTopSegment) || thisTopSegment.Intersects(otherBottomSegment) || thisBottomSegment.Intersects(otherTopSegment) || thisBottomSegment.Intersects(otherBottomSegment)) { return(true); } #endregion #region Point vs. Segment (T collision) if ( thisTopSegment.DistanceTo(otherEndpoint1.X, otherEndpoint1.Y) < otherCapsule.mEndpointRadius || thisTopSegment.DistanceTo(otherEndpoint2.X, otherEndpoint2.Y) < otherCapsule.mEndpointRadius || thisBottomSegment.DistanceTo(otherEndpoint1.X, otherEndpoint1.Y) < otherCapsule.mEndpointRadius || thisBottomSegment.DistanceTo(otherEndpoint2.X, otherEndpoint2.Y) < otherCapsule.mEndpointRadius) { return(true); } if ( otherTopSegment.DistanceTo(thisEndpoint1.X, thisEndpoint1.Y) < this.mEndpointRadius || otherTopSegment.DistanceTo(thisEndpoint2.X, thisEndpoint2.Y) < this.mEndpointRadius || otherBottomSegment.DistanceTo(thisEndpoint1.X, thisEndpoint1.Y) < this.mEndpointRadius || otherBottomSegment.DistanceTo(thisEndpoint2.X, thisEndpoint2.Y) < this.mEndpointRadius) { return(true); } #endregion #region Endpoint inside Shape (Fully contained collision) Point thisEndpoint1Point = new Point(ref thisEndpoint1); Point thisEndpoint2Point = new Point(ref thisEndpoint2); Point otherEndpoint1Point = new Point(ref otherEndpoint1); Point otherEndpoint2Point = new Point(ref otherEndpoint2); if ( MathFunctions.IsPointInsideRectangle(thisEndpoint1Point, otherTopSegment.Point1, otherTopSegment.Point2, otherBottomSegment.Point2, otherBottomSegment.Point1) || MathFunctions.IsPointInsideRectangle(thisEndpoint2Point, otherTopSegment.Point1, otherTopSegment.Point2, otherBottomSegment.Point2, otherBottomSegment.Point1) || MathFunctions.IsPointInsideRectangle(otherEndpoint1Point, thisTopSegment.Point1, thisTopSegment.Point2, thisBottomSegment.Point2, thisBottomSegment.Point1) || MathFunctions.IsPointInsideRectangle(otherEndpoint2Point, thisTopSegment.Point1, thisTopSegment.Point2, thisBottomSegment.Point2, thisBottomSegment.Point1) ) { return(true); } #endregion // If we got here then the two do not touch. return(false); }