Advertisement
Guest User

Collision.cpp

a guest
Aug 22nd, 2012
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.65 KB | None | 0 0
  1. /*
  2. * File: collision.cpp
  3. * Author: Nick
  4. *
  5. * Created on 30 January 2009, 11:02
  6. */
  7. #include <SFML/Graphics.hpp>
  8. #include "Collision.h"
  9.  
  10. Collision::Collision() {
  11. }
  12.  
  13. Collision::~Collision() {
  14. }
  15.  
  16. sf::IntRect Collision::GetAABB(const sf::Sprite& Object) {
  17.  
  18. //Get the top left corner of the sprite regardless of the sprite's center
  19. //This is in Global Coordinates so we can put the rectangle back into the right place
  20. sf::Vector2f pos = Object.transformToGlobal(sf::Vector2f(0, 0));
  21.  
  22. //Store the size so we can calculate the other corners
  23. sf::Vector2f size = Object.getSize();
  24.  
  25. float Angle = Object.getRotation();
  26.  
  27. //Bail out early if the sprite isn't rotated
  28. if (Angle == 0.0f) {
  29. return sf::IntRect(static_cast<int> (pos.x),
  30. static_cast<int> (pos.y),
  31. static_cast<int> (pos.x + size.x),
  32. static_cast<int> (pos.y + size.y));
  33. }
  34.  
  35. //Calculate the other points as vectors from (0,0)
  36. //Imagine sf::Vector2f A(0,0); but its not necessary
  37. //as rotation is around this point.
  38. sf::Vector2f B(size.x, 0);
  39. sf::Vector2f C(size.x, size.y);
  40. sf::Vector2f D(0, size.y);
  41.  
  42. //Rotate the points to match the sprite rotation
  43. B = RotatePoint(B, Angle);
  44. C = RotatePoint(C, Angle);
  45. D = RotatePoint(D, Angle);
  46.  
  47. //Round off to int and set the four corners of our Rect
  48. int Left = static_cast<int> (MinValue(0.0f, B.x, C.x, D.x));
  49. int Top = static_cast<int> (MinValue(0.0f, B.y, C.y, D.y));
  50. int Right = static_cast<int> (MaxValue(0.0f, B.x, C.x, D.x));
  51. int Bottom = static_cast<int> (MaxValue(0.0f, B.y, C.y, D.y));
  52.  
  53. //Create a Rect from out points and move it back to the correct position on the screen
  54. sf::IntRect AABB = sf::IntRect(Left, Top, Right, Bottom);
  55. AABB.Offset(static_cast<int> (pos.x), static_cast<int> (pos.y));
  56. return AABB;
  57. }
  58.  
  59. float Collision::MinValue(float a, float b, float c, float d) {
  60. float min = a;
  61.  
  62. min = (b < min ? b : min);
  63. min = (c < min ? c : min);
  64. min = (d < min ? d : min);
  65.  
  66. return min;
  67. }
  68.  
  69. float Collision::MaxValue(float a, float b, float c, float d) {
  70. float max = a;
  71.  
  72. max = (b > max ? b : max);
  73. max = (c > max ? c : max);
  74. max = (d > max ? d : max);
  75.  
  76. return max;
  77. }
  78.  
  79. sf::Vector2f Collision::RotatePoint(const sf::Vector2f& Point, float Angle) {
  80. Angle = Angle * RADIANS_PER_DEGREE;
  81. sf::Vector2f RotatedPoint;
  82. RotatedPoint.x = Point.x * cos(Angle) + Point.y * sin(Angle);
  83. RotatedPoint.y = -Point.x * sin(Angle) + Point.y * cos(Angle);
  84. return RotatedPoint;
  85. }
  86.  
  87. bool Collision::PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
  88. //Get AABBs of the two sprites
  89. sf::IntRect Object1AABB = GetAABB(Object1);
  90. sf::IntRect Object2AABB = GetAABB(Object2);
  91.  
  92. sf::IntRect Intersection;
  93.  
  94. if (Object1AABB.intersects(Object2AABB, &Intersection)) {
  95.  
  96. //We've got an intersection we need to process the pixels
  97. //In that Rect.
  98.  
  99. //Bail out now if AlphaLimit = 0
  100. if (AlphaLimit == 0) return true;
  101.  
  102. //There are a few hacks here, sometimes the TransformToLocal returns negative points
  103. //Or Points outside the image. We need to check for these as they print to the error console
  104. //which is slow, and then return black which registers as a hit.
  105.  
  106. sf::IntRect O1SubRect = Object1.getSubRect();
  107. sf::IntRect O2SubRect = Object2.getSubRect();
  108.  
  109. sf::Vector2i O1SubRectSize(O1SubRect.getWidth(), O1SubRect.getHeight());
  110. sf::Vector2i O2SubRectSize(O2SubRect.getWidth(), O2SubRect.getHeight());
  111.  
  112. sf::Vector2f o1v;
  113. sf::Vector2f o2v;
  114. //Loop through our pixels
  115. for (int i = Intersection.left; i < Intersection.right; i++) {
  116. for (int j = Intersection.top; j < Intersection.bottom; j++) {
  117.  
  118. o1v = Object1.transformToLocal(sf::Vector2f(i, j)); //Creating Objects each loop :(
  119. o2v = Object2.transformToLocal(sf::Vector2f(i, j));
  120.  
  121. //Hack to make sure pixels fall withint the Sprite's Image
  122. if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
  123. o1v.x < O1SubRectSize.x && o1v.y < O1SubRectSize.y &&
  124. o2v.x < O2SubRectSize.x && o2v.y < O2SubRectSize.y) {
  125.  
  126. //If both sprites have opaque pixels at the same point we've got a hit
  127. if ((Object1.getPixel(static_cast<int> (o1v.x), static_cast<int> (o1v.y)).a > AlphaLimit) &&
  128. (Object2.getPixel(static_cast<int> (o2v.x), static_cast<int> (o2v.y)).a > AlphaLimit)) {
  129. return true;
  130. }
  131. }
  132. }
  133. }
  134. return false;
  135. }
  136. return false;
  137. }
  138.  
  139. bool Collision::CircleTest(const sf::Sprite& Object1, const sf::Sprite& Object2) {
  140. //Simplest circle test possible
  141. //Distance between points <= sum of radius
  142.  
  143. float Radius1 = (Object1.getSize().x + Object1.getSize().y) / 4;
  144. float Radius2 = (Object2.getSize().x + Object2.getSize().y) / 4;
  145. float xd = Object1.getPosition().x - Object2.getPosition().x;
  146. float yd = Object1.getPosition().y - Object2.getPosition().y;
  147.  
  148. return sqrt(xd * xd + yd * yd) <= Radius1 + Radius2;
  149. }
  150.  
  151. //From Rotated Rectangles Collision Detection, Oren Becker, 2001
  152.  
  153. bool Collision::BoundingBoxTest(const sf::Sprite& Object1, const sf::Sprite& Object2) {
  154.  
  155. sf::Vector2f A, B, C, BL, TR;
  156. sf::Vector2f HalfSize1 = Object1.getSize();
  157. sf::Vector2f HalfSize2 = Object2.getSize();
  158.  
  159. //For somereason the Vector2d divide by operator
  160. //was misbehaving
  161. //Doing it manually
  162. HalfSize1.x /= 2;
  163. HalfSize1.y /= 2;
  164. HalfSize2.x /= 2;
  165. HalfSize2.y /= 2;
  166. //Get the Angle we're working on
  167. float Angle = Object1.getRotation() - Object2.getRotation();
  168. float CosA = cos(Angle * RADIANS_PER_DEGREE);
  169. float SinA = sin(Angle * RADIANS_PER_DEGREE);
  170.  
  171. float t, x, a, dx, ext1, ext2;
  172.  
  173. //Normalise the Center of Object2 so its axis aligned an represented in
  174. //relation to Object 1
  175. C = Object2.getPosition();
  176.  
  177. C -= Object1.getPosition();
  178.  
  179. C = RotatePoint(C, Object2.getRotation());
  180.  
  181. //Get the Corners
  182. BL = TR = C;
  183. BL -= HalfSize2;
  184. TR += HalfSize2;
  185.  
  186. //Calculate the vertices of the rotate Rect
  187. A.x = -HalfSize1.y*SinA;
  188. B.x = A.x;
  189. t = HalfSize1.x*CosA;
  190. A.x += t;
  191. B.x -= t;
  192.  
  193. A.y = HalfSize1.y*CosA;
  194. B.y = A.y;
  195. t = HalfSize1.x*SinA;
  196. A.y += t;
  197. B.y -= t;
  198.  
  199. t = SinA * CosA;
  200.  
  201. // verify that A is vertical min/max, B is horizontal min/max
  202. if (t < 0) {
  203. t = A.x;
  204. A.x = B.x;
  205. B.x = t;
  206. t = A.y;
  207. A.y = B.y;
  208. B.y = t;
  209. }
  210.  
  211. // verify that B is horizontal minimum (leftest-vertex)
  212. if (SinA < 0) {
  213. B.x = -B.x;
  214. B.y = -B.y;
  215. }
  216.  
  217. // if rr2(ma) isn't in the horizontal range of
  218. // colliding with rr1(r), collision is impossible
  219. if (B.x > TR.x || B.x > -BL.x) return false;
  220.  
  221. // if rr1(r) is axis-aligned, vertical min/max are easy to get
  222. if (t == 0) {
  223. ext1 = A.y;
  224. ext2 = -ext1;
  225. }// else, find vertical min/max in the range [BL.x, TR.x]
  226. else {
  227. x = BL.x - A.x;
  228. a = TR.x - A.x;
  229. ext1 = A.y;
  230. // if the first vertical min/max isn't in (BL.x, TR.x), then
  231. // find the vertical min/max on BL.x or on TR.x
  232. if (a * x > 0) {
  233. dx = A.x;
  234. if (x < 0) {
  235. dx -= B.x;
  236. ext1 -= B.y;
  237. x = a;
  238. } else {
  239. dx += B.x;
  240. ext1 += B.y;
  241. }
  242. ext1 *= x;
  243. ext1 /= dx;
  244. ext1 += A.y;
  245. }
  246.  
  247. x = BL.x + A.x;
  248. a = TR.x + A.x;
  249. ext2 = -A.y;
  250. // if the second vertical min/max isn't in (BL.x, TR.x), then
  251. // find the local vertical min/max on BL.x or on TR.x
  252. if (a * x > 0) {
  253. dx = -A.x;
  254. if (x < 0) {
  255. dx -= B.x;
  256. ext2 -= B.y;
  257. x = a;
  258. } else {
  259. dx += B.x;
  260. ext2 += B.y;
  261. }
  262. ext2 *= x;
  263. ext2 /= dx;
  264. ext2 -= A.y;
  265. }
  266. }
  267.  
  268. // check whether rr2(ma) is in the vertical range of colliding with rr1(r)
  269. // (for the horizontal range of rr2)
  270. return !((ext1 < BL.y && ext2 < BL.y) ||
  271. (ext1 > TR.y && ext2 > TR.y));
  272.  
  273. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement