CollisionMath.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. //-----------------------------------------------------------------------------
  2. // CollisionMath.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using Microsoft.Xna.Framework;
  9. namespace NetRumble
  10. {
  11. /// <summary>
  12. /// A code container for collision-related mathematical functions.
  13. /// </summary>
  14. static public class CollisionMath
  15. {
  16. /// <summary>
  17. /// Data defining a circle/line collision result.
  18. /// </summary>
  19. /// <remarks>Also used for circle/rectangles.</remarks>
  20. public struct CircleLineCollisionResult
  21. {
  22. public bool Collision;
  23. public Vector2 Point;
  24. public Vector2 Normal;
  25. public float Distance;
  26. }
  27. /// <summary>
  28. /// Determines the point of intersection between two line segments,
  29. /// as defined by four points.
  30. /// </summary>
  31. /// <param name="a">The first point on the first line segment.</param>
  32. /// <param name="b">The second point on the first line segment.</param>
  33. /// <param name="c">The first point on the second line segment.</param>
  34. /// <param name="d">The second point on the second line segment.</param>
  35. /// <param name="point">The output value with the interesection, if any.</param>
  36. /// <remarks>The output parameter "point" is only valid
  37. /// when the return value is true.</remarks>
  38. /// <returns>True if intersecting, false otherwise.</returns>
  39. public static bool LineLineIntersect(Vector2 a, Vector2 b, Vector2 c,
  40. Vector2 d, out Vector2 point)
  41. {
  42. point = Vector2.Zero;
  43. double r, s;
  44. double denominator = (b.X - a.X) * (d.Y - c.Y) - (b.Y - a.Y) * (d.X - c.X);
  45. // If the denominator in above is zero, AB & CD are colinear
  46. if (denominator == 0)
  47. {
  48. return false;
  49. }
  50. double numeratorR = (a.Y - c.Y) * (d.X - c.X) - (a.X - c.X) * (d.Y - c.Y);
  51. r = numeratorR / denominator;
  52. double numeratorS = (a.Y - c.Y) * (b.X - a.X) - (a.X - c.X) * (b.Y - a.Y);
  53. s = numeratorS / denominator;
  54. // non-intersecting
  55. if (r < 0 || r > 1 || s < 0 || s > 1)
  56. {
  57. return false;
  58. }
  59. // find intersection point
  60. point.X = (float)(a.X + (r * (b.X - a.X)));
  61. point.Y = (float)(a.Y + (r * (b.Y - a.Y)));
  62. return true;
  63. }
  64. /// <summary>
  65. /// Determine if two circles intersect or contain each other.
  66. /// </summary>
  67. /// <param name="center1">The center of the first circle.</param>
  68. /// <param name="radius1">The radius of the first circle.</param>
  69. /// <param name="center2">The center of the second circle.</param>
  70. /// <param name="radius2">The radius of the second circle.</param>
  71. /// <returns>True if the circles intersect or contain one another.</returns>
  72. public static bool CircleCircleIntersect(Vector2 center1, float radius1,
  73. Vector2 center2, float radius2)
  74. {
  75. Vector2 line = center2 - center1;
  76. // we use LengthSquared to avoid a costly square-root call
  77. return (line.LengthSquared() <= (radius1 + radius2) * (radius1 + radius2));
  78. }
  79. /// <summary>
  80. /// Determines if a circle and line segment intersect, and if so, how they do.
  81. /// </summary>
  82. /// <param name="center">The center of the circle.</param>
  83. /// <param name="radius">The radius of the circle.</param>
  84. /// <param name="rectangle">The rectangle.</param>
  85. /// <param name="result">The result data for the collision.</param>
  86. /// <returns>True if a collision occurs, provided for convenience.</returns>
  87. public static bool CircleRectangleCollide(Vector2 center, float radius,
  88. Rectangle rectangle, ref CircleLineCollisionResult result)
  89. {
  90. float xVal = center.X;
  91. if (xVal < rectangle.Left) xVal = rectangle.Left;
  92. if (xVal > rectangle.Right) xVal = rectangle.Right;
  93. float yVal = center.Y;
  94. if (yVal < rectangle.Top) yVal = rectangle.Top;
  95. if (yVal > rectangle.Bottom) yVal = rectangle.Bottom;
  96. Vector2 direction = new Vector2(center.X-xVal,center.Y-yVal);
  97. float distance = direction.Length();
  98. if ((distance > 0) && (distance < radius))
  99. {
  100. result.Collision = true;
  101. result.Distance = radius - distance;
  102. result.Normal = Vector2.Normalize(direction);
  103. result.Point = new Vector2(xVal, yVal);
  104. }
  105. else
  106. {
  107. result.Collision = false;
  108. }
  109. return result.Collision;
  110. }
  111. /// <summary>
  112. /// Determines if a circle and line segment intersect, and if so, how they do.
  113. /// </summary>
  114. /// <param name="center">The center of the circle.</param>
  115. /// <param name="radius">The radius of the circle.</param>
  116. /// <param name="lineStart">The first point on the line segment.</param>
  117. /// <param name="lineEnd">The second point on the line segment.</param>
  118. /// <param name="result">The result data for the collision.</param>
  119. /// <returns>True if a collision occurs, provided for convenience.</returns>
  120. public static bool CircleLineCollide(Vector2 center, float radius,
  121. Vector2 lineStart, Vector2 lineEnd, ref CircleLineCollisionResult result)
  122. {
  123. Vector2 AC = center - lineStart;
  124. Vector2 AB = lineEnd - lineStart;
  125. float ab2 = AB.LengthSquared();
  126. if (ab2 <= 0f)
  127. {
  128. return false;
  129. }
  130. float acab = Vector2.Dot(AC, AB);
  131. float t = acab / ab2;
  132. if (t < 0.0f)
  133. t = 0.0f;
  134. else if (t > 1.0f)
  135. t = 1.0f;
  136. result.Point = lineStart + t * AB;
  137. result.Normal = center - result.Point;
  138. float h2 = result.Normal.LengthSquared();
  139. float r2 = radius * radius;
  140. if ((h2 > 0) && (h2 <= r2))
  141. {
  142. result.Normal.Normalize();
  143. result.Distance = (radius - (center - result.Point).Length());
  144. result.Collision = true;
  145. }
  146. else
  147. {
  148. result.Collision = false;
  149. }
  150. return result.Collision;
  151. }
  152. }
  153. }