ContactManager.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * Farseer Physics Engine based on Box2D.XNA port:
  3. * Copyright (c) 2010 Ian Qvist
  4. *
  5. * Box2D.XNA port of Box2D:
  6. * Copyright (c) 2009 Brandon Furtwangler, Nathan Furtwangler
  7. *
  8. * Original source Box2D:
  9. * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
  10. *
  11. * This software is provided 'as-is', without any express or implied
  12. * warranty. In no event will the authors be held liable for any damages
  13. * arising from the use of this software.
  14. * Permission is granted to anyone to use this software for any purpose,
  15. * including commercial applications, and to alter it and redistribute it
  16. * freely, subject to the following restrictions:
  17. * 1. The origin of this software must not be misrepresented; you must not
  18. * claim that you wrote the original software. If you use this software
  19. * in a product, an acknowledgment in the product documentation would be
  20. * appreciated but is not required.
  21. * 2. Altered source versions must be plainly marked as such, and must not be
  22. * misrepresented as being the original software.
  23. * 3. This notice may not be removed or altered from any source distribution.
  24. */
  25. using System.Collections.Generic;
  26. using FarseerPhysics.Collision;
  27. using FarseerPhysics.Dynamics.Contacts;
  28. namespace FarseerPhysics.Dynamics
  29. {
  30. public class ContactManager
  31. {
  32. /// <summary>
  33. /// Fires when a contact is created
  34. /// </summary>
  35. public BeginContactDelegate BeginContact;
  36. public IBroadPhase BroadPhase;
  37. /// <summary>
  38. /// The filter used by the contact manager.
  39. /// </summary>
  40. public CollisionFilterDelegate ContactFilter;
  41. public List<Contact> ContactList = new List<Contact>(128);
  42. /// <summary>
  43. /// Fires when a contact is deleted
  44. /// </summary>
  45. public EndContactDelegate EndContact;
  46. /// <summary>
  47. /// Fires when the broadphase detects that two Fixtures are close to each other.
  48. /// </summary>
  49. public BroadphaseDelegate OnBroadphaseCollision;
  50. /// <summary>
  51. /// Fires after the solver has run
  52. /// </summary>
  53. public PostSolveDelegate PostSolve;
  54. /// <summary>
  55. /// Fires before the solver runs
  56. /// </summary>
  57. public PreSolveDelegate PreSolve;
  58. internal ContactManager(IBroadPhase broadPhase)
  59. {
  60. BroadPhase = broadPhase;
  61. OnBroadphaseCollision = AddPair;
  62. }
  63. // Broad-phase callback.
  64. private void AddPair(ref FixtureProxy proxyA, ref FixtureProxy proxyB)
  65. {
  66. Fixture fixtureA = proxyA.Fixture;
  67. Fixture fixtureB = proxyB.Fixture;
  68. int indexA = proxyA.ChildIndex;
  69. int indexB = proxyB.ChildIndex;
  70. Body bodyA = fixtureA.Body;
  71. Body bodyB = fixtureB.Body;
  72. // Are the fixtures on the same body?
  73. if (bodyA == bodyB)
  74. {
  75. return;
  76. }
  77. // Does a contact already exist?
  78. ContactEdge edge = bodyB.ContactList;
  79. while (edge != null)
  80. {
  81. if (edge.Other == bodyA)
  82. {
  83. Fixture fA = edge.Contact.FixtureA;
  84. Fixture fB = edge.Contact.FixtureB;
  85. int iA = edge.Contact.ChildIndexA;
  86. int iB = edge.Contact.ChildIndexB;
  87. if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
  88. {
  89. // A contact already exists.
  90. return;
  91. }
  92. if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)
  93. {
  94. // A contact already exists.
  95. return;
  96. }
  97. }
  98. edge = edge.Next;
  99. }
  100. // Does a joint override collision? Is at least one body dynamic?
  101. if (bodyB.ShouldCollide(bodyA) == false)
  102. return;
  103. //Check default filter
  104. if (ShouldCollide(fixtureA, fixtureB) == false)
  105. return;
  106. // Check user filtering.
  107. if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false)
  108. return;
  109. if (fixtureA.BeforeCollision != null && fixtureA.BeforeCollision(fixtureA, fixtureB) == false)
  110. return;
  111. if (fixtureB.BeforeCollision != null && fixtureB.BeforeCollision(fixtureB, fixtureA) == false)
  112. return;
  113. // Call the factory.
  114. Contact c = Contact.Create(fixtureA, indexA, fixtureB, indexB);
  115. // Contact creation may swap fixtures.
  116. fixtureA = c.FixtureA;
  117. fixtureB = c.FixtureB;
  118. bodyA = fixtureA.Body;
  119. bodyB = fixtureB.Body;
  120. // Insert into the world.
  121. ContactList.Add(c);
  122. // Connect to island graph.
  123. // Connect to body A
  124. c.NodeA.Contact = c;
  125. c.NodeA.Other = bodyB;
  126. c.NodeA.Prev = null;
  127. c.NodeA.Next = bodyA.ContactList;
  128. if (bodyA.ContactList != null)
  129. {
  130. bodyA.ContactList.Prev = c.NodeA;
  131. }
  132. bodyA.ContactList = c.NodeA;
  133. // Connect to body B
  134. c.NodeB.Contact = c;
  135. c.NodeB.Other = bodyA;
  136. c.NodeB.Prev = null;
  137. c.NodeB.Next = bodyB.ContactList;
  138. if (bodyB.ContactList != null)
  139. {
  140. bodyB.ContactList.Prev = c.NodeB;
  141. }
  142. bodyB.ContactList = c.NodeB;
  143. }
  144. internal void FindNewContacts()
  145. {
  146. BroadPhase.UpdatePairs(OnBroadphaseCollision);
  147. }
  148. internal void Destroy(Contact contact)
  149. {
  150. Fixture fixtureA = contact.FixtureA;
  151. Fixture fixtureB = contact.FixtureB;
  152. Body bodyA = fixtureA.Body;
  153. Body bodyB = fixtureB.Body;
  154. if (EndContact != null && contact.IsTouching())
  155. {
  156. EndContact(contact);
  157. }
  158. // Remove from the world.
  159. ContactList.Remove(contact);
  160. // Remove from body 1
  161. if (contact.NodeA.Prev != null)
  162. {
  163. contact.NodeA.Prev.Next = contact.NodeA.Next;
  164. }
  165. if (contact.NodeA.Next != null)
  166. {
  167. contact.NodeA.Next.Prev = contact.NodeA.Prev;
  168. }
  169. if (contact.NodeA == bodyA.ContactList)
  170. {
  171. bodyA.ContactList = contact.NodeA.Next;
  172. }
  173. // Remove from body 2
  174. if (contact.NodeB.Prev != null)
  175. {
  176. contact.NodeB.Prev.Next = contact.NodeB.Next;
  177. }
  178. if (contact.NodeB.Next != null)
  179. {
  180. contact.NodeB.Next.Prev = contact.NodeB.Prev;
  181. }
  182. if (contact.NodeB == bodyB.ContactList)
  183. {
  184. bodyB.ContactList = contact.NodeB.Next;
  185. }
  186. contact.Destroy();
  187. }
  188. internal void Collide()
  189. {
  190. // Update awake contacts.
  191. for (int i = 0; i < ContactList.Count; i++)
  192. {
  193. Contact c = ContactList[i];
  194. Fixture fixtureA = c.FixtureA;
  195. Fixture fixtureB = c.FixtureB;
  196. int indexA = c.ChildIndexA;
  197. int indexB = c.ChildIndexB;
  198. Body bodyA = fixtureA.Body;
  199. Body bodyB = fixtureB.Body;
  200. if (bodyA.Awake == false && bodyB.Awake == false)
  201. {
  202. continue;
  203. }
  204. // Is this contact flagged for filtering?
  205. if ((c.Flags & ContactFlags.Filter) == ContactFlags.Filter)
  206. {
  207. // Should these bodies collide?
  208. if (bodyB.ShouldCollide(bodyA) == false)
  209. {
  210. Contact cNuke = c;
  211. Destroy(cNuke);
  212. continue;
  213. }
  214. // Check default filtering
  215. if (ShouldCollide(fixtureA, fixtureB) == false)
  216. {
  217. Contact cNuke = c;
  218. Destroy(cNuke);
  219. continue;
  220. }
  221. // Check user filtering.
  222. if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false)
  223. {
  224. Contact cNuke = c;
  225. Destroy(cNuke);
  226. continue;
  227. }
  228. // Clear the filtering flag.
  229. c.Flags &= ~ContactFlags.Filter;
  230. }
  231. int proxyIdA = fixtureA.Proxies[indexA].ProxyId;
  232. int proxyIdB = fixtureB.Proxies[indexB].ProxyId;
  233. bool overlap = BroadPhase.TestOverlap(proxyIdA, proxyIdB);
  234. // Here we destroy contacts that cease to overlap in the broad-phase.
  235. if (overlap == false)
  236. {
  237. Contact cNuke = c;
  238. Destroy(cNuke);
  239. continue;
  240. }
  241. // The contact persists.
  242. c.Update(this);
  243. }
  244. }
  245. private static bool ShouldCollide(Fixture fixtureA, Fixture fixtureB)
  246. {
  247. if (Settings.UseFPECollisionCategories)
  248. {
  249. if ((fixtureA.CollisionGroup == fixtureB.CollisionGroup) &&
  250. fixtureA.CollisionGroup != 0 && fixtureB.CollisionGroup != 0)
  251. return false;
  252. if (((fixtureA.CollisionCategories & fixtureB.CollidesWith) ==
  253. Category.None) &
  254. ((fixtureB.CollisionCategories & fixtureA.CollidesWith) ==
  255. Category.None))
  256. return false;
  257. if (fixtureA.IsFixtureIgnored(fixtureB) ||
  258. fixtureB.IsFixtureIgnored(fixtureA))
  259. return false;
  260. return true;
  261. }
  262. if (fixtureA.CollisionGroup == fixtureB.CollisionGroup &&
  263. fixtureA.CollisionGroup != 0)
  264. {
  265. return fixtureA.CollisionGroup > 0;
  266. }
  267. bool collide = (fixtureA.CollidesWith & fixtureB.CollisionCategories) != 0 &&
  268. (fixtureA.CollisionCategories & fixtureB.CollidesWith) != 0;
  269. if (collide)
  270. {
  271. if (fixtureA.IsFixtureIgnored(fixtureB) ||
  272. fixtureB.IsFixtureIgnored(fixtureA))
  273. {
  274. return false;
  275. }
  276. }
  277. return collide;
  278. }
  279. }
  280. }