PageRenderTime 763ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/Big McGreed/Big McGreed/logic/utility/RotatedRectangle.cs

http://big-mcgreed.googlecode.com/
C# | 277 lines | 146 code | 26 blank | 105 comment | 6 complexity | b1cdbdd3441194832d7f60bfd2549976 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Microsoft.Xna.Framework;
  6. namespace Big_McGreed.utility
  7. {
  8. /// <summary>
  9. /// Represents a rotated rectangle.
  10. /// </summary>
  11. public class RotatedRectangle
  12. {
  13. private Rectangle collisionRectangle;
  14. private float rotation;
  15. private Vector2 origin;
  16. /// <summary>
  17. /// Initializes a new instance of the <see cref="RotatedRectangle"/> class.
  18. /// </summary>
  19. /// <param name="rectangle">The rectangle.</param>
  20. /// <param name="rotation">The rotation.</param>
  21. public RotatedRectangle(Rectangle rectangle, float rotation)
  22. {
  23. collisionRectangle = rectangle;
  24. this.rotation = rotation;
  25. //Calculate the Rectangles origin. We assume the center of the Rectangle will
  26. //be the point that we will be rotating around and we use that for the origin
  27. origin = new Vector2(0f, 0f);
  28. }
  29. /// <summary>
  30. /// Used for changing the X and Y position of the RotatedRectangle
  31. /// </summary>
  32. /// <param name="theXPositionAdjustment">The X position adjustment.</param>
  33. /// <param name="theYPositionAdjustment">The Y position adjustment.</param>
  34. public void ChangePosition(int theXPositionAdjustment, int theYPositionAdjustment)
  35. {
  36. collisionRectangle.X += theXPositionAdjustment;
  37. collisionRectangle.Y += theYPositionAdjustment;
  38. }
  39. /// <summary>
  40. /// This intersects method can be used to check a standard XNA framework Rectangle
  41. /// object and see if it collides with a Rotated Rectangle object
  42. /// </summary>
  43. /// <param name="theRectangle">The rectangle.</param>
  44. /// <returns></returns>
  45. public bool Intersects(Rectangle theRectangle)
  46. {
  47. return Intersects(new RotatedRectangle(theRectangle, 0.0f));
  48. }
  49. /// <summary>
  50. /// Check to see if two Rotated Rectangls have collided
  51. /// </summary>
  52. /// <param name="theRectangle">The rectangle.</param>
  53. /// <returns></returns>
  54. public bool Intersects(RotatedRectangle theRectangle)
  55. {
  56. //Calculate the Axis we will use to determine if a collision has occurred
  57. //Since the objects are rectangles, we only have to generate 4 Axis (2 for
  58. //each rectangle) since we know the other 2 on a rectangle are parallel.
  59. List<Vector2> aRectangleAxis = new List<Vector2>();
  60. aRectangleAxis.Add(UpperRightCorner() - UpperLeftCorner());
  61. aRectangleAxis.Add(UpperRightCorner() - LowerRightCorner());
  62. aRectangleAxis.Add(theRectangle.UpperLeftCorner() - theRectangle.LowerLeftCorner());
  63. aRectangleAxis.Add(theRectangle.UpperLeftCorner() - theRectangle.UpperRightCorner());
  64. //Cycle through all of the Axis we need to check. If a collision does not occur
  65. //on ALL of the Axis, then a collision is NOT occurring. We can then exit out
  66. //immediately and notify the calling function that no collision was detected. If
  67. //a collision DOES occur on ALL of the Axis, then there is a collision occurring
  68. //between the rotated rectangles. We know this to be true by the Seperating Axis Theorem
  69. foreach (Vector2 aAxis in aRectangleAxis)
  70. {
  71. if (!IsAxisCollision(theRectangle, aAxis))
  72. {
  73. return false;
  74. }
  75. }
  76. return true;
  77. }
  78. /// <summary>
  79. /// Determines if a collision has occurred on an Axis of one of the
  80. /// planes parallel to the Rectangle
  81. /// </summary>
  82. /// <param name="theRectangle">The rectangle.</param>
  83. /// <param name="aAxis">A axis.</param>
  84. /// <returns>
  85. /// <c>true</c> if [is axis collision] [the specified the rectangle]; otherwise, <c>false</c>.
  86. /// </returns>
  87. private bool IsAxisCollision(RotatedRectangle theRectangle, Vector2 aAxis)
  88. {
  89. //Project the corners of the Rectangle we are checking on to the Axis and
  90. //get a scalar value of that project we can then use for comparison
  91. List<int> aRectangleAScalars = new List<int>();
  92. aRectangleAScalars.Add(GenerateScalar(theRectangle.UpperLeftCorner(), aAxis));
  93. aRectangleAScalars.Add(GenerateScalar(theRectangle.UpperRightCorner(), aAxis));
  94. aRectangleAScalars.Add(GenerateScalar(theRectangle.LowerLeftCorner(), aAxis));
  95. aRectangleAScalars.Add(GenerateScalar(theRectangle.LowerRightCorner(), aAxis));
  96. //Project the corners of the current Rectangle on to the Axis and
  97. //get a scalar value of that project we can then use for comparison
  98. List<int> aRectangleBScalars = new List<int>();
  99. aRectangleBScalars.Add(GenerateScalar(UpperLeftCorner(), aAxis));
  100. aRectangleBScalars.Add(GenerateScalar(UpperRightCorner(), aAxis));
  101. aRectangleBScalars.Add(GenerateScalar(LowerLeftCorner(), aAxis));
  102. aRectangleBScalars.Add(GenerateScalar(LowerRightCorner(), aAxis));
  103. //Get the Maximum and Minium Scalar values for each of the Rectangles
  104. int aRectangleAMinimum = aRectangleAScalars.Min();
  105. int aRectangleAMaximum = aRectangleAScalars.Max();
  106. int aRectangleBMinimum = aRectangleBScalars.Min();
  107. int aRectangleBMaximum = aRectangleBScalars.Max();
  108. //If we have overlaps between the Rectangles (i.e. Min of B is less than Max of A)
  109. //then we are detecting a collision between the rectangles on this Axis
  110. if (aRectangleBMinimum <= aRectangleAMaximum && aRectangleBMaximum >= aRectangleAMaximum)
  111. {
  112. return true;
  113. }
  114. else if (aRectangleAMinimum <= aRectangleBMaximum && aRectangleAMaximum >= aRectangleBMaximum)
  115. {
  116. return true;
  117. }
  118. return false;
  119. }
  120. /// <summary>
  121. /// Generates a scalar value that can be used to compare where corners of
  122. /// a rectangle have been projected onto a particular axis.
  123. /// </summary>
  124. /// <param name="theRectangleCorner">The rectangle corner.</param>
  125. /// <param name="theAxis">The axis.</param>
  126. /// <returns></returns>
  127. private int GenerateScalar(Vector2 theRectangleCorner, Vector2 theAxis)
  128. {
  129. //Using the formula for Vector projection. Take the corner being passed in
  130. //and project it onto the given Axis
  131. float aNumerator = (theRectangleCorner.X * theAxis.X) + (theRectangleCorner.Y * theAxis.Y);
  132. float aDenominator = (theAxis.X * theAxis.X) + (theAxis.Y * theAxis.Y);
  133. float aDivisionResult = aNumerator / aDenominator;
  134. Vector2 aCornerProjected = new Vector2(aDivisionResult * theAxis.X, aDivisionResult * theAxis.Y);
  135. //Now that we have our projected Vector, calculate a scalar of that projection
  136. //that can be used to more easily do comparisons
  137. float aScalar = (theAxis.X * aCornerProjected.X) + (theAxis.Y * aCornerProjected.Y);
  138. return (int)aScalar;
  139. }
  140. /// <summary>
  141. /// Rotate a point from a given location and adjust using the Origin we
  142. /// are rotating around
  143. /// </summary>
  144. /// <param name="thePoint">The point.</param>
  145. /// <param name="theOrigin">The origin.</param>
  146. /// <param name="theRotation">The rotation.</param>
  147. /// <returns></returns>
  148. private Vector2 RotatePoint(Vector2 thePoint, Vector2 theOrigin, float theRotation)
  149. {
  150. Vector2 aTranslatedPoint = new Vector2();
  151. aTranslatedPoint.X = (float)(theOrigin.X + (thePoint.X - theOrigin.X) * Math.Cos(theRotation)
  152. - (thePoint.Y - theOrigin.Y) * Math.Sin(theRotation));
  153. aTranslatedPoint.Y = (float)(theOrigin.Y + (thePoint.Y - theOrigin.Y) * Math.Cos(theRotation)
  154. + (thePoint.X - theOrigin.X) * Math.Sin(theRotation));
  155. return aTranslatedPoint;
  156. }
  157. public List<Vector2> RectanglePoints
  158. {
  159. get
  160. {
  161. return new List<Vector2>()
  162. {
  163. LowerRightCorner(),
  164. UpperLeftCorner(),
  165. UpperRightCorner(),
  166. LowerLeftCorner()
  167. };
  168. }
  169. }
  170. /// <summary>
  171. /// Calclate the upper left corner.
  172. /// </summary>
  173. /// <returns>
  174. /// The upper left corner
  175. /// </returns>
  176. public Vector2 UpperLeftCorner()
  177. {
  178. Vector2 aUpperLeft = new Vector2(collisionRectangle.Left, collisionRectangle.Top);
  179. aUpperLeft = RotatePoint(aUpperLeft, aUpperLeft + origin, rotation);
  180. return aUpperLeft;
  181. }
  182. /// <summary>
  183. /// Calclate the upper right corner.
  184. /// </summary>
  185. /// <returns>
  186. /// The upper right corner
  187. /// </returns>
  188. public Vector2 UpperRightCorner()
  189. {
  190. Vector2 aUpperRight = new Vector2(collisionRectangle.Right, collisionRectangle.Top);
  191. aUpperRight = RotatePoint(aUpperRight, aUpperRight + new Vector2(-origin.X, origin.Y), rotation);
  192. return aUpperRight;
  193. }
  194. /// <summary>
  195. /// Calclate the lower left corner.
  196. /// </summary>
  197. /// <returns>
  198. /// The lower left corner
  199. /// </returns>
  200. public Vector2 LowerLeftCorner()
  201. {
  202. Vector2 aLowerLeft = new Vector2(collisionRectangle.Left, collisionRectangle.Bottom);
  203. aLowerLeft = RotatePoint(aLowerLeft, aLowerLeft + new Vector2(origin.X, -origin.Y), rotation);
  204. return aLowerLeft;
  205. }
  206. /// <summary>
  207. /// Calclate the lower right corner.
  208. /// </summary>
  209. /// <returns>
  210. /// The lower right corner
  211. /// </returns>
  212. public Vector2 LowerRightCorner()
  213. {
  214. Vector2 aLowerRight = new Vector2(collisionRectangle.Right, collisionRectangle.Bottom);
  215. aLowerRight = RotatePoint(aLowerRight, aLowerRight + new Vector2(-origin.X, -origin.Y), rotation);
  216. return aLowerRight;
  217. }
  218. /// <summary>
  219. /// Gets the X.
  220. /// </summary>
  221. public int X
  222. {
  223. get { return collisionRectangle.X; }
  224. }
  225. /// <summary>
  226. /// Gets the Y.
  227. /// </summary>
  228. public int Y
  229. {
  230. get { return collisionRectangle.Y; }
  231. }
  232. /// <summary>
  233. /// Gets the width.
  234. /// </summary>
  235. public int Width
  236. {
  237. get { return collisionRectangle.Width; }
  238. }
  239. /// <summary>
  240. /// Gets the height.
  241. /// </summary>
  242. public int Height
  243. {
  244. get { return collisionRectangle.Height; }
  245. }
  246. public Rectangle CollisionRetangle
  247. {
  248. get { return collisionRectangle; }
  249. }
  250. }
  251. }