public bool IntersectsWith(IConvexShape shape) { //so it won't enter a call-loop of infinite proportions if (shape.GetType() == typeof(Point)) { return(this == (Point)shape); } else //call Shape's better suited sat check { return(shape.IntersectsWith(this)); } }
/// <summary> /// Returns whether this shape overlaps with another somewhere if it moves by relativeSpeed. /// Returns the fraction of the speed given at which they touch and the axis closest to this touching point (from either shape). /// The fraction will be -1f if there's an overlap but no collision caused by the relativeSpeed. /// </summary> public bool IntersectsWith(IConvexShape shape, Point relativeSpeed, out float touchingAtSpeedFraction, out Point intersectionAxis) { touchingAtSpeedFraction = float.PositiveInfinity; intersectionAxis = Point.Zero; Type shape1Type = GetType(); Type shape2Type = shape.GetType(); //2 AABB's or ComplexRectangles without a rotation (so basically AABB's) if ((shape1Type == typeof(Rectangle) || shape1Type == typeof(ComplexRectangle) && _Rotation == 0f) && (shape2Type == typeof(Rectangle) || shape2Type == typeof(ComplexRectangle) && ((Shape)shape)._Rotation == 0f)) { Rectangle rect1 = (Rectangle)this; Rectangle rect2 = (Rectangle)shape; float xTouchingFraction, yTouchingFraction; if (relativeSpeed.X >= 0f) { if (rect1.Position2.X + relativeSpeed.X < rect2.Position.X || rect1.Position.X > rect2.Position2.X) { return(false); } xTouchingFraction = (rect2.Position.X - rect1.Position2.X) / relativeSpeed.X; } else { if (rect1.Position.X + relativeSpeed.X > rect2.Position2.X || rect1.Position2.X < rect2.Position.X) { return(false); } xTouchingFraction = (rect2.Position2.X - rect1.Position.X) / relativeSpeed.X; } if (relativeSpeed.Y >= 0f) { if (rect1.Position2.Y + relativeSpeed.Y < rect2.Position.Y || rect1.Position.Y > rect2.Position2.Y) { return(false); } yTouchingFraction = (rect2.Position.Y - rect1.Position2.Y) / relativeSpeed.Y; } else { if (rect1.Position.Y + relativeSpeed.Y > rect2.Position2.Y || rect1.Position2.Y < rect2.Position.Y) { return(false); } yTouchingFraction = (rect2.Position2.Y - rect1.Position.Y) / relativeSpeed.Y; } //decide which fraction and corresponding axis to return, if any if (xTouchingFraction >= 0f && xTouchingFraction <= 1f) { touchingAtSpeedFraction = xTouchingFraction; intersectionAxis = rect2.GetPerpAxes()[0]; } if (yTouchingFraction >= 0f && yTouchingFraction <= 1f && yTouchingFraction < touchingAtSpeedFraction) { touchingAtSpeedFraction = yTouchingFraction; intersectionAxis = rect2.GetPerpAxes()[1]; } if (intersectionAxis == Point.Zero) { touchingAtSpeedFraction = -1f; } return(true); } else //other shapes { touchingAtSpeedFraction = float.PositiveInfinity; Point[] shape1Points = GetPoints(); Point[] shape2Points = shape.GetPoints(); List <Point> allAxes = new List <Point>(GetPerpAxes()); allAxes.AddRange(shape.GetPerpAxes()); foreach (Point axis in allAxes) { float shape1ScalarMin = float.PositiveInfinity; float shape1ScalarMax = float.NegativeInfinity; float shape2ScalarMin = float.PositiveInfinity; float shape2ScalarMax = float.NegativeInfinity; //cast shape1's points to the axis foreach (Point point in shape1Points) { float multiplier = (float)((point.X * axis.X + point.Y * axis.Y) / (axis.X * axis.X + axis.Y * axis.Y)); float scalar = multiplier * axis.X * axis.X + multiplier * axis.Y * axis.Y; if (scalar < shape1ScalarMin) { shape1ScalarMin = scalar; } if (scalar > shape1ScalarMax) { shape1ScalarMax = scalar; } } //cast shape2's points to the axis foreach (Point point in shape2Points) { float multiplier = (float)((point.X * axis.X + point.Y * axis.Y) / (axis.X * axis.X + axis.Y * axis.Y)); float scalar = multiplier * axis.X * axis.X + multiplier * axis.Y * axis.Y; if (scalar < shape2ScalarMin) { shape2ScalarMin = scalar; } if (scalar > shape2ScalarMax) { shape2ScalarMax = scalar; } } //cast speed to axis float speedMultiplier = (float)((relativeSpeed.X * axis.X + relativeSpeed.Y * axis.Y) / (axis.X * axis.X + axis.Y * axis.Y)); float speedScalar = speedMultiplier * axis.X * axis.X + speedMultiplier * axis.Y * axis.Y; float thisTouchingAtSpeedFraction; if (speedScalar >= 0) { if (shape1ScalarMax + speedScalar < shape2ScalarMin || shape1ScalarMin > shape2ScalarMax) { return(false); } thisTouchingAtSpeedFraction = (shape2ScalarMin - shape1ScalarMax) / speedScalar; } else { if (shape1ScalarMin + speedScalar > shape2ScalarMax || shape1ScalarMax < shape2ScalarMin) { return(false); } thisTouchingAtSpeedFraction = (shape2ScalarMax - shape1ScalarMin) / speedScalar; } if (thisTouchingAtSpeedFraction >= 0f && thisTouchingAtSpeedFraction <= 1f && thisTouchingAtSpeedFraction < touchingAtSpeedFraction) { touchingAtSpeedFraction = thisTouchingAtSpeedFraction; intersectionAxis = axis; } } if (intersectionAxis == Point.Zero) { touchingAtSpeedFraction = -1f; } else //this axis is still a perpendicular axis, revert! { intersectionAxis = new Point(intersectionAxis.Y, -intersectionAxis.X); } return(true); } }
/// <summary> /// Returns whether this shape overlaps with another somewhere if it moves by relativeSpeed. /// Returns the fraction of the speed given at which they touch and the axis closest to this touching point (from either shape). /// The fraction will be -1f if there's an overlap but no collision caused by the relativeSpeed. /// </summary> public bool IntersectsWith(IConvexShape shape, Point relativeSpeed, out float touchingAtSpeedFraction, out Point intersectionAxis) { touchingAtSpeedFraction = float.PositiveInfinity; intersectionAxis = Point.Zero; Type shape1Type = GetType(); Type shape2Type = shape.GetType(); //2 AABB's or ComplexRectangles without a rotation (so basically AABB's) if ((shape1Type == typeof(Rectangle) || shape1Type == typeof(ComplexRectangle) && _Rotation == 0f) && (shape2Type == typeof(Rectangle) || shape2Type == typeof(ComplexRectangle) && ((Shape)shape)._Rotation == 0f)) { Rectangle rect1 = (Rectangle)this; Rectangle rect2 = (Rectangle)shape; float xTouchingFraction, yTouchingFraction; if (relativeSpeed.X >= 0f) { if (rect1.Position2.X + relativeSpeed.X < rect2.Position.X || rect1.Position.X > rect2.Position2.X) return false; xTouchingFraction = (rect2.Position.X - rect1.Position2.X) / relativeSpeed.X; } else { if (rect1.Position.X + relativeSpeed.X > rect2.Position2.X || rect1.Position2.X < rect2.Position.X) return false; xTouchingFraction = (rect2.Position2.X - rect1.Position.X) / relativeSpeed.X; } if (relativeSpeed.Y >= 0f) { if (rect1.Position2.Y + relativeSpeed.Y < rect2.Position.Y || rect1.Position.Y > rect2.Position2.Y) return false; yTouchingFraction = (rect2.Position.Y - rect1.Position2.Y) / relativeSpeed.Y; } else { if (rect1.Position.Y + relativeSpeed.Y > rect2.Position2.Y || rect1.Position2.Y < rect2.Position.Y) return false; yTouchingFraction = (rect2.Position2.Y - rect1.Position.Y) / relativeSpeed.Y; } //decide which fraction and corresponding axis to return, if any if (xTouchingFraction >= 0f && xTouchingFraction <= 1f) { touchingAtSpeedFraction = xTouchingFraction; intersectionAxis = rect2.GetPerpAxes()[0]; } if (yTouchingFraction >= 0f && yTouchingFraction <= 1f && yTouchingFraction < touchingAtSpeedFraction) { touchingAtSpeedFraction = yTouchingFraction; intersectionAxis = rect2.GetPerpAxes()[1]; } if (intersectionAxis == Point.Zero) touchingAtSpeedFraction = -1f; return true; } //other shapes touchingAtSpeedFraction = float.PositiveInfinity; Point[] shape1Points = GetPoints(); Point[] shape2Points = shape.GetPoints(); List<Point> allAxes = new List<Point>(GetPerpAxes()); allAxes.AddRange(shape.GetPerpAxes()); foreach (Point axis in allAxes) { float shape1ScalarMin = float.PositiveInfinity; float shape1ScalarMax = float.NegativeInfinity; float shape2ScalarMin = float.PositiveInfinity; float shape2ScalarMax = float.NegativeInfinity; //cast shape1's points to the axis foreach (Point point in shape1Points) { float multiplier = (float)((point.X * axis.X + point.Y * axis.Y) / (axis.X * axis.X + axis.Y * axis.Y)); float scalar = multiplier * axis.X * axis.X + multiplier * axis.Y * axis.Y; if (scalar < shape1ScalarMin) shape1ScalarMin = scalar; if (scalar > shape1ScalarMax) shape1ScalarMax = scalar; } //cast shape2's points to the axis foreach (Point point in shape2Points) { float multiplier = (float)((point.X * axis.X + point.Y * axis.Y) / (axis.X * axis.X + axis.Y * axis.Y)); float scalar = multiplier * axis.X * axis.X + multiplier * axis.Y * axis.Y; if (scalar < shape2ScalarMin) shape2ScalarMin = scalar; if (scalar > shape2ScalarMax) shape2ScalarMax = scalar; } //cast speed to axis float speedMultiplier = (float)((relativeSpeed.X * axis.X + relativeSpeed.Y * axis.Y) / (axis.X * axis.X + axis.Y * axis.Y)); float speedScalar = speedMultiplier * axis.X * axis.X + speedMultiplier * axis.Y * axis.Y; float thisTouchingAtSpeedFraction; if (speedScalar >= 0) { if (shape1ScalarMax + speedScalar < shape2ScalarMin || shape1ScalarMin > shape2ScalarMax) return false; thisTouchingAtSpeedFraction = (shape2ScalarMin - shape1ScalarMax) / speedScalar; } else { if (shape1ScalarMin + speedScalar > shape2ScalarMax || shape1ScalarMax < shape2ScalarMin) return false; thisTouchingAtSpeedFraction = (shape2ScalarMax - shape1ScalarMin) / speedScalar; } if (thisTouchingAtSpeedFraction >= 0f && thisTouchingAtSpeedFraction <= 1f && thisTouchingAtSpeedFraction < touchingAtSpeedFraction) { touchingAtSpeedFraction = thisTouchingAtSpeedFraction; intersectionAxis = axis; } } if (intersectionAxis == Point.Zero) touchingAtSpeedFraction = -1f; else //this axis is still a perpendicular axis, revert! intersectionAxis = new Point(intersectionAxis.Y, -intersectionAxis.X); return true; }