ContactManager.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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. namespace Box2D.XNA
  24. {
  25. public class ContactManager
  26. {
  27. internal ContactManager()
  28. {
  29. _addPair = AddPair;
  30. _contactList = null;
  31. _contactCount = 0;
  32. ContactFilter = new DefaultContactFilter();
  33. ContactListener = new DefaultContactListener();
  34. }
  35. // Broad-phase callback.
  36. internal void AddPair(FixtureProxy proxyA, FixtureProxy proxyB)
  37. {
  38. Fixture fixtureA = proxyA.fixture;
  39. Fixture fixtureB = proxyB.fixture;
  40. int indexA = proxyA.childIndex;
  41. int indexB = proxyB.childIndex;
  42. Body bodyA = fixtureA.GetBody();
  43. Body bodyB = fixtureB.GetBody();
  44. // Are the fixtures on the same body?
  45. if (bodyA == bodyB)
  46. {
  47. return;
  48. }
  49. // Does a contact already exist?
  50. ContactEdge edge = bodyB.GetContactList();
  51. while (edge != null)
  52. {
  53. if (edge.Other == bodyA)
  54. {
  55. Fixture fA = edge.Contact.GetFixtureA();
  56. Fixture fB = edge.Contact.GetFixtureB();
  57. int iA = edge.Contact.GetChildIndexA();
  58. int iB = edge.Contact.GetChildIndexB();
  59. if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
  60. {
  61. // A contact already exists.
  62. return;
  63. }
  64. if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)
  65. {
  66. // A contact already exists.
  67. return;
  68. }
  69. }
  70. edge = edge.Next;
  71. }
  72. // Does a joint override collision? Is at least one body dynamic?
  73. if (bodyB.ShouldCollide(bodyA) == false)
  74. {
  75. return;
  76. }
  77. // Check user filtering.
  78. if (ContactFilter != null && ContactFilter.ShouldCollide(fixtureA, fixtureB) == false)
  79. {
  80. return;
  81. }
  82. // Call the factory.
  83. Contact c = Contact.Create(fixtureA, indexA, fixtureB, indexB);
  84. // Contact creation may swap fixtures.
  85. fixtureA = c.GetFixtureA();
  86. fixtureB = c.GetFixtureB();
  87. indexA = c.GetChildIndexA();
  88. indexB = c.GetChildIndexB();
  89. bodyA = fixtureA.GetBody();
  90. bodyB = fixtureB.GetBody();
  91. // Insert into the world.
  92. c._prev = null;
  93. c._next = _contactList;
  94. if (_contactList != null)
  95. {
  96. _contactList._prev = c;
  97. }
  98. _contactList = c;
  99. // Connect to island graph.
  100. // Connect to body A
  101. c._nodeA.Contact = c;
  102. c._nodeA.Other = bodyB;
  103. c._nodeA.Prev = null;
  104. c._nodeA.Next = bodyA._contactList;
  105. if (bodyA._contactList != null)
  106. {
  107. bodyA._contactList.Prev = c._nodeA;
  108. }
  109. bodyA._contactList = c._nodeA;
  110. // Connect to body B
  111. c._nodeB.Contact = c;
  112. c._nodeB.Other = bodyA;
  113. c._nodeB.Prev = null;
  114. c._nodeB.Next = bodyB._contactList;
  115. if (bodyB._contactList != null)
  116. {
  117. bodyB._contactList.Prev = c._nodeB;
  118. }
  119. bodyB._contactList = c._nodeB;
  120. ++_contactCount;
  121. }
  122. internal void FindNewContacts()
  123. {
  124. _broadPhase.UpdatePairs<FixtureProxy>(_addPair);
  125. }
  126. internal void Destroy(Contact c)
  127. {
  128. Fixture fixtureA = c.GetFixtureA();
  129. Fixture fixtureB = c.GetFixtureB();
  130. Body bodyA = fixtureA.GetBody();
  131. Body bodyB = fixtureB.GetBody();
  132. if (ContactListener != null && c.IsTouching())
  133. {
  134. ContactListener.EndContact(c);
  135. }
  136. // Remove from the world.
  137. if (c._prev != null)
  138. {
  139. c._prev._next = c._next;
  140. }
  141. if (c._next != null)
  142. {
  143. c._next._prev = c._prev;
  144. }
  145. if (c == _contactList)
  146. {
  147. _contactList = c._next;
  148. }
  149. // Remove from body 1
  150. if (c._nodeA.Prev != null)
  151. {
  152. c._nodeA.Prev.Next = c._nodeA.Next;
  153. }
  154. if (c._nodeA.Next != null)
  155. {
  156. c._nodeA.Next.Prev = c._nodeA.Prev;
  157. }
  158. if (c._nodeA == bodyA._contactList)
  159. {
  160. bodyA._contactList = c._nodeA.Next;
  161. }
  162. // Remove from body 2
  163. if (c._nodeB.Prev != null)
  164. {
  165. c._nodeB.Prev.Next = c._nodeB.Next;
  166. }
  167. if (c._nodeB.Next != null)
  168. {
  169. c._nodeB.Next.Prev = c._nodeB.Prev;
  170. }
  171. if (c._nodeB == bodyB._contactList)
  172. {
  173. bodyB._contactList = c._nodeB.Next;
  174. }
  175. c.Destroy();
  176. --_contactCount;
  177. }
  178. internal void Collide()
  179. {
  180. // Update awake contacts.
  181. Contact c = _contactList;
  182. while (c != null)
  183. {
  184. Fixture fixtureA = c.GetFixtureA();
  185. Fixture fixtureB = c.GetFixtureB();
  186. int indexA = c.GetChildIndexA();
  187. int indexB = c.GetChildIndexB();
  188. Body bodyA = fixtureA.GetBody();
  189. Body bodyB = fixtureB.GetBody();
  190. if (bodyA.IsAwake() == false && bodyB.IsAwake() == false)
  191. {
  192. c = c.GetNext();
  193. continue;
  194. }
  195. // Is this contact flagged for filtering?
  196. if ((c._flags & ContactFlags.Filter) == ContactFlags.Filter)
  197. {
  198. // Should these bodies collide?
  199. if (bodyB.ShouldCollide(bodyA) == false)
  200. {
  201. Contact cNuke = c;
  202. c = cNuke.GetNext();
  203. Destroy(cNuke);
  204. continue;
  205. }
  206. // Check user filtering.
  207. if (ContactFilter != null && ContactFilter.ShouldCollide(fixtureA, fixtureB) == false)
  208. {
  209. Contact cNuke = c;
  210. c = cNuke.GetNext();
  211. Destroy(cNuke);
  212. continue;
  213. }
  214. // Clear the filtering flag.
  215. c._flags &= ~ContactFlags.Filter;
  216. }
  217. int proxyIdA = fixtureA._proxies[indexA].proxyId;
  218. int proxyIdB = fixtureB._proxies[indexB].proxyId;
  219. bool overlap = _broadPhase.TestOverlap(proxyIdA, proxyIdB);
  220. // Here we destroy contacts that cease to overlap in the broad-phase.
  221. if (overlap == false)
  222. {
  223. Contact cNuke = c;
  224. c = cNuke.GetNext();
  225. Destroy(cNuke);
  226. continue;
  227. }
  228. // The contact persists.
  229. c.Update(ContactListener);
  230. c = c.GetNext();
  231. }
  232. }
  233. internal BroadPhase _broadPhase = new BroadPhase();
  234. internal Contact _contactList;
  235. internal int _contactCount;
  236. internal IContactFilter ContactFilter { get; set; }
  237. internal IContactListener ContactListener { get; set; }
  238. Action<FixtureProxy, FixtureProxy> _addPair;
  239. }
  240. }