CollisionMath.cs 7.0 KB

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