Contact.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*
  2. * Box2D.XNA port of Box2D:
  3. * Copyright (c) 2009 Brandon Furtwangler, Nathan Furtwangler
  4. *
  5. * Original source Box2D:
  6. * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
  7. *
  8. * This software is provided 'as-is', without any express or implied
  9. * warranty. In no event will the authors be held liable for any damages
  10. * arising from the use of this software.
  11. * Permission is granted to anyone to use this software for any purpose,
  12. * including commercial applications, and to alter it and redistribute it
  13. * freely, subject to the following restrictions:
  14. * 1. The origin of this software must not be misrepresented; you must not
  15. * claim that you wrote the original software. If you use this software
  16. * in a product, an acknowledgment in the product documentation would be
  17. * appreciated but is not required.
  18. * 2. Altered source versions must be plainly marked as such, and must not be
  19. * misrepresented as being the original software.
  20. * 3. This notice may not be removed or altered from any source distribution.
  21. */
  22. using System;
  23. using System.Diagnostics;
  24. using System.Collections.Generic;
  25. namespace Box2D.XNA
  26. {
  27. /// A contact edge is used to connect bodies and contacts together
  28. /// in a contact graph where each body is a node and each contact
  29. /// is an edge. A contact edge belongs to a doubly linked list
  30. /// maintained in each attached body. Each contact has two contact
  31. /// nodes, one for each attached body.
  32. public class ContactEdge
  33. {
  34. public Body Other; ///< provides quick access to the other body attached.
  35. public Contact Contact; ///< the contact
  36. public ContactEdge Prev; ///< the previous contact edge in the body's contact list
  37. public ContactEdge Next; ///< the next contact edge in the body's contact list
  38. };
  39. [Flags]
  40. public enum ContactFlags
  41. {
  42. None = 0,
  43. // Used when crawling contact graph when forming islands.
  44. Island = 0x0001,
  45. // Set when the shapes are touching.
  46. Touching = 0x0002,
  47. // This contact can be disabled (by user)
  48. Enabled = 0x0004,
  49. // This contact needs filtering because a fixture filter was changed.
  50. Filter = 0x0008,
  51. // This bullet contact had a TOI event
  52. BulletHit = 0x0010,
  53. };
  54. /// The class manages contact between two shapes. A contact exists for each overlapping
  55. /// AABB in the broad-phase (except if filtered). Therefore a contact object may exist
  56. /// that has no contact points.
  57. public class Contact
  58. {
  59. /// Get the contact manifold. Do not modify the manifold unless you understand the
  60. /// internals of Box2D.
  61. public void GetManifold(out Manifold manifold)
  62. {
  63. manifold = _manifold;
  64. }
  65. /// Get the world manifold.
  66. public void GetWorldManifold(out WorldManifold worldManifold)
  67. {
  68. Body bodyA = _fixtureA.GetBody();
  69. Body bodyB = _fixtureB.GetBody();
  70. Shape shapeA = _fixtureA.GetShape();
  71. Shape shapeB = _fixtureB.GetShape();
  72. Transform xfA, xfB;
  73. bodyA.GetTransform(out xfA);
  74. bodyB.GetTransform(out xfB);
  75. worldManifold = new WorldManifold(ref _manifold, ref xfA, shapeA._radius, ref xfB, shapeB._radius);
  76. }
  77. /// Is this contact touching?
  78. public bool IsTouching()
  79. {
  80. return (_flags & ContactFlags.Touching) == ContactFlags.Touching;
  81. }
  82. /// Enable/disable this contact. This can be used inside the pre-solve
  83. /// contact listener. The contact is only disabled for the current
  84. /// time step (or sub-step in continuous collisions).
  85. public void SetEnabled(bool flag)
  86. {
  87. if (flag)
  88. {
  89. _flags |= ContactFlags.Enabled;
  90. }
  91. else
  92. {
  93. _flags &= ~ContactFlags.Enabled;
  94. }
  95. }
  96. /// Has this contact been disabled?
  97. public bool IsEnabled()
  98. {
  99. return (_flags & ContactFlags.Enabled) == ContactFlags.Enabled;
  100. }
  101. /// Get the next contact in the world's contact list.
  102. public Contact GetNext()
  103. {
  104. return _next;
  105. }
  106. /// Get fixture A in this contact.
  107. public Fixture GetFixtureA()
  108. {
  109. return _fixtureA;
  110. }
  111. /// Get fixture B in this contact.
  112. public Fixture GetFixtureB()
  113. {
  114. return _fixtureB;
  115. }
  116. /// Get the child primitive index for fixture A.
  117. public int GetChildIndexA()
  118. {
  119. return _indexA;
  120. }
  121. /// Get the child primitive index for fixture B.
  122. public int GetChildIndexB()
  123. {
  124. return _indexB;
  125. }
  126. /// Flag this contact for filtering. Filtering will occur the next time step.
  127. public void FlagForFiltering()
  128. {
  129. _flags |= ContactFlags.Filter;
  130. }
  131. internal Contact(Fixture fA, int indexA, Fixture fB, int indexB)
  132. {
  133. Reset(fA, indexA, fB, indexB);
  134. }
  135. internal void Reset(Fixture fA, int indexA, Fixture fB, int indexB)
  136. {
  137. _flags = ContactFlags.Enabled;
  138. _fixtureA = fA;
  139. _fixtureB = fB;
  140. _indexA = indexA;
  141. _indexB = indexB;
  142. _manifold._pointCount = 0;
  143. _prev = null;
  144. _next = null;
  145. _nodeA.Contact = null;
  146. _nodeA.Prev = null;
  147. _nodeA.Next = null;
  148. _nodeA.Other = null;
  149. _nodeB.Contact = null;
  150. _nodeB.Prev = null;
  151. _nodeB.Next = null;
  152. _nodeB.Other = null;
  153. _toiCount = 0;
  154. }
  155. // Update the contact manifold and touching status.
  156. // Note: do not assume the fixture AABBs are overlapping or are valid.
  157. internal void Update(IContactListener listener)
  158. {
  159. Manifold oldManifold = _manifold;
  160. // Re-enable this contact.
  161. _flags |= ContactFlags.Enabled;
  162. bool touching = false;
  163. bool wasTouching = (_flags & ContactFlags.Touching) == ContactFlags.Touching;
  164. bool sensorA = _fixtureA.IsSensor();
  165. bool sensorB = _fixtureB.IsSensor();
  166. bool sensor = sensorA || sensorB;
  167. Body bodyA = _fixtureA.GetBody();
  168. Body bodyB = _fixtureB.GetBody();
  169. Transform xfA; bodyA.GetTransform(out xfA);
  170. Transform xfB; bodyB.GetTransform(out xfB);
  171. // Is this contact a sensor?
  172. if (sensor)
  173. {
  174. Shape shapeA = _fixtureA.GetShape();
  175. Shape shapeB = _fixtureB.GetShape();
  176. touching = AABB.TestOverlap(shapeA, _indexA, shapeB, _indexB, ref xfA, ref xfB);
  177. // Sensors don't generate manifolds.
  178. _manifold._pointCount = 0;
  179. }
  180. else
  181. {
  182. Evaluate(ref _manifold, ref xfA, ref xfB);
  183. touching = _manifold._pointCount > 0;
  184. // Match old contact ids to new contact ids and copy the
  185. // stored impulses to warm start the solver.
  186. for (int i = 0; i < _manifold._pointCount; ++i)
  187. {
  188. ManifoldPoint mp2 = _manifold._points[i];
  189. mp2.NormalImpulse = 0.0f;
  190. mp2.TangentImpulse = 0.0f;
  191. ContactID id2 = mp2.Id;
  192. bool found = false;
  193. for (int j = 0; j < oldManifold._pointCount; ++j)
  194. {
  195. ManifoldPoint mp1 = oldManifold._points[j];
  196. if (mp1.Id.Key == id2.Key)
  197. {
  198. mp2.NormalImpulse = mp1.NormalImpulse;
  199. mp2.TangentImpulse = mp1.TangentImpulse;
  200. found = true;
  201. break;
  202. }
  203. }
  204. if (found == false)
  205. {
  206. mp2.NormalImpulse = 0.0f;
  207. mp2.TangentImpulse = 0.0f;
  208. }
  209. _manifold._points[i] = mp2;
  210. }
  211. if (touching != wasTouching)
  212. {
  213. bodyA.SetAwake(true);
  214. bodyB.SetAwake(true);
  215. }
  216. }
  217. if (touching)
  218. {
  219. _flags |= ContactFlags.Touching;
  220. }
  221. else
  222. {
  223. _flags &= ~ContactFlags.Touching;
  224. }
  225. if (wasTouching == false && touching == true && null != listener)
  226. {
  227. listener.BeginContact(this);
  228. }
  229. if (wasTouching == true && touching == false && null != listener)
  230. {
  231. listener.EndContact(this);
  232. }
  233. if (sensor == false && null != listener)
  234. {
  235. listener.PreSolve(this, ref oldManifold);
  236. }
  237. }
  238. private static EdgeShape s_edge = new EdgeShape();
  239. /// Evaluate this contact with your own manifold and transforms.
  240. internal void Evaluate(ref Manifold manifold, ref Transform xfA, ref Transform xfB)
  241. {
  242. switch (_type)
  243. {
  244. case ContactType.Polygon:
  245. Collision.CollidePolygons(ref manifold,
  246. (PolygonShape)_fixtureA.GetShape(), ref xfA,
  247. (PolygonShape)_fixtureB.GetShape(), ref xfB);
  248. break;
  249. case ContactType.PolygonAndCircle:
  250. Collision.CollidePolygonAndCircle(ref manifold,
  251. (PolygonShape)_fixtureA.GetShape(), ref xfA,
  252. (CircleShape) _fixtureB.GetShape(), ref xfB);
  253. break;
  254. case ContactType.EdgeAndCircle:
  255. Collision.CollideEdgeAndCircle(ref manifold,
  256. (EdgeShape) _fixtureA.GetShape(), ref xfA,
  257. (CircleShape)_fixtureB.GetShape(), ref xfB);
  258. break;
  259. case ContactType.EdgeAndPolygon:
  260. Collision.CollideEdgeAndPolygon(ref manifold,
  261. (EdgeShape) _fixtureA.GetShape(), ref xfA,
  262. (PolygonShape)_fixtureB.GetShape(), ref xfB);
  263. break;
  264. case ContactType.LoopAndCircle:
  265. var loop = (LoopShape)_fixtureA.GetShape();
  266. loop.GetChildEdge(ref s_edge, _indexA);
  267. Collision.CollideEdgeAndCircle(ref manifold, s_edge, ref xfA,
  268. (CircleShape)_fixtureB.GetShape(), ref xfB);
  269. break;
  270. case ContactType.LoopAndPolygon:
  271. var loop2 = (LoopShape)_fixtureA.GetShape();
  272. loop2.GetChildEdge(ref s_edge, _indexA);
  273. Collision.CollideEdgeAndPolygon(ref manifold, s_edge, ref xfA,
  274. (PolygonShape)_fixtureB.GetShape(), ref xfB);
  275. break;
  276. case ContactType.Circle:
  277. Collision.CollideCircles(ref manifold,
  278. (CircleShape)_fixtureA.GetShape(), ref xfA,
  279. (CircleShape)_fixtureB.GetShape(), ref xfB);
  280. break;
  281. }
  282. }
  283. internal enum ContactType
  284. {
  285. Polygon,
  286. PolygonAndCircle,
  287. Circle,
  288. EdgeAndPolygon,
  289. EdgeAndCircle,
  290. LoopAndPolygon,
  291. LoopAndCircle,
  292. }
  293. /*public enum ShapeType
  294. {
  295. Unknown = -1,
  296. Circle = 0,
  297. Edge = 1,
  298. Polygon = 2,
  299. Loop = 3,
  300. TypeCount = 4,
  301. };*/
  302. internal static ContactType[,] s_registers = new ContactType[,]
  303. {
  304. {
  305. ContactType.Circle,
  306. ContactType.EdgeAndCircle,
  307. ContactType.PolygonAndCircle,
  308. ContactType.LoopAndCircle,
  309. },
  310. {
  311. ContactType.EdgeAndCircle,
  312. ContactType.EdgeAndCircle, // 1,1 is invalid (no ContactType.Edge)
  313. ContactType.EdgeAndPolygon,
  314. ContactType.EdgeAndPolygon, // 1,3 is invalid (no ContactType.EdgeAndLoop)
  315. },
  316. {
  317. ContactType.PolygonAndCircle,
  318. ContactType.EdgeAndPolygon,
  319. ContactType.Polygon,
  320. ContactType.LoopAndPolygon,
  321. },
  322. {
  323. ContactType.LoopAndCircle,
  324. ContactType.LoopAndCircle, // 3,1 is invalid (no ContactType.EdgeAndLoop)
  325. ContactType.LoopAndPolygon,
  326. ContactType.LoopAndPolygon, // 3,3 is invalid (no ContactType.Loop)
  327. },
  328. };
  329. internal static Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB)
  330. {
  331. ShapeType type1 = fixtureA.ShapeType;
  332. ShapeType type2 = fixtureB.ShapeType;
  333. Debug.Assert(ShapeType.Unknown < type1 && type1 < ShapeType.TypeCount);
  334. Debug.Assert(ShapeType.Unknown < type2 && type2 < ShapeType.TypeCount);
  335. Contact c;
  336. var pool = fixtureA._body._world._contactPool;
  337. if (pool.Count > 0)
  338. {
  339. c = pool.Dequeue();
  340. if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon))
  341. &&
  342. !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon))
  343. {
  344. c.Reset(fixtureA, indexA, fixtureB, indexB);
  345. }
  346. else
  347. {
  348. c.Reset(fixtureB, indexB, fixtureA, indexA);
  349. }
  350. }
  351. else
  352. {
  353. // Edge+Polygon is non-symetrical due to the way Erin handles collision type registration.
  354. if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon))
  355. &&
  356. !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon))
  357. {
  358. c = new Contact(fixtureA, indexA, fixtureB, indexB);
  359. }
  360. else
  361. {
  362. c = new Contact(fixtureB, indexB, fixtureA, indexA);
  363. }
  364. }
  365. c._type = Contact.s_registers[(int)type1, (int)type2];
  366. return c;
  367. }
  368. internal void Destroy()
  369. {
  370. _fixtureA._body._world._contactPool.Enqueue(this);
  371. Reset(null, 0, null, 0);
  372. }
  373. private ContactType _type;
  374. internal ContactFlags _flags;
  375. // World pool and list pointers.
  376. internal Contact _prev;
  377. internal Contact _next;
  378. // Nodes for connecting bodies.
  379. internal ContactEdge _nodeA = new ContactEdge();
  380. internal ContactEdge _nodeB = new ContactEdge();
  381. internal Fixture _fixtureA;
  382. internal Fixture _fixtureB;
  383. internal int _indexA;
  384. internal int _indexB;
  385. internal Manifold _manifold;
  386. internal int _toiCount;
  387. };
  388. }