Island.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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 Microsoft.Xna.Framework;
  25. namespace Box2D.XNA
  26. {
  27. /// This is an internal class.
  28. class Island
  29. {
  30. public Island() { }
  31. public void Reset(int bodyCapacity, int contactCapacity, int jointCapacity, IContactListener listener)
  32. {
  33. _bodyCapacity = bodyCapacity;
  34. _contactCapacity = contactCapacity;
  35. _jointCapacity = jointCapacity;
  36. _bodyCount = 0;
  37. _jointCount = 0;
  38. _listener = listener;
  39. if (_bodies == null || _bodies.Length < bodyCapacity)
  40. {
  41. _bodies = new Body[bodyCapacity];
  42. }
  43. if (_contacts == null || _contacts.Length < contactCapacity)
  44. {
  45. _contacts = new Contact[contactCapacity * 2];
  46. }
  47. if (_joints == null || _joints.Length < jointCapacity)
  48. {
  49. _joints = new Joint[jointCapacity * 2];
  50. }
  51. }
  52. public void Clear()
  53. {
  54. _bodyCount = 0;
  55. _contactCount = 0;
  56. _jointCount = 0;
  57. }
  58. public void Solve(ref TimeStep step, Vector2 gravity, bool allowSleep)
  59. {
  60. // Integrate velocities and apply damping.
  61. for (int i = 0; i < _bodyCount; ++i)
  62. {
  63. Body b = _bodies[i];
  64. if (b.GetType() != BodyType.Dynamic)
  65. {
  66. continue;
  67. }
  68. // Integrate velocities.
  69. b._linearVelocity += step.dt * (gravity + b._invMass * b._force);
  70. b._angularVelocity += step.dt * b._invI * b._torque;
  71. // Apply damping.
  72. // ODE: dv/dt + c * v = 0
  73. // Solution: v(t) = v0 * exp(-c * t)
  74. // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
  75. // v2 = exp(-c * dt) * v1
  76. // Taylor expansion:
  77. // v2 = (1.0f - c * dt) * v1
  78. b._linearVelocity *= MathUtils.Clamp(1.0f - step.dt * b._linearDamping, 0.0f, 1.0f);
  79. b._angularVelocity *= MathUtils.Clamp(1.0f - step.dt * b._angularDamping, 0.0f, 1.0f);
  80. }
  81. // Partition contacts so that contacts with static bodies are solved last.
  82. int i1 = -1;
  83. for (int i2 = 0; i2 < _contactCount; ++i2)
  84. {
  85. Fixture fixtureA = _contacts[i2].GetFixtureA();
  86. Fixture fixtureB = _contacts[i2].GetFixtureB();
  87. Body bodyA = fixtureA.GetBody();
  88. Body bodyB = fixtureB.GetBody();
  89. bool nonStatic = bodyA.GetType() != BodyType.Static && bodyB.GetType() != BodyType.Static;
  90. if (nonStatic)
  91. {
  92. ++i1;
  93. //b2Swap(_contacts[i1], _contacts[i2]);
  94. Contact temp = _contacts[i1];
  95. _contacts[i1] = _contacts[i2];
  96. _contacts[i2] = temp;
  97. }
  98. }
  99. // Initialize velocity constraints.
  100. _contactSolver.Reset(_contacts, _contactCount, step.dtRatio);
  101. _contactSolver.WarmStart();
  102. for (int i = 0; i < _jointCount; ++i)
  103. {
  104. _joints[i].InitVelocityConstraints(ref step);
  105. }
  106. // Solve velocity constraints.
  107. for (int i = 0; i < step.velocityIterations; ++i)
  108. {
  109. for (int j = 0; j < _jointCount; ++j)
  110. {
  111. _joints[j].SolveVelocityConstraints(ref step);
  112. }
  113. _contactSolver.SolveVelocityConstraints();
  114. }
  115. // Post-solve (store impulses for warm starting).
  116. _contactSolver.StoreImpulses();
  117. // Integrate positions.
  118. for (int i = 0; i < _bodyCount; ++i)
  119. {
  120. Body b = _bodies[i];
  121. if (b.GetType() == BodyType.Static)
  122. {
  123. continue;
  124. }
  125. // Check for large velocities.
  126. Vector2 translation = step.dt * b._linearVelocity;
  127. if (Vector2.Dot(translation, translation) > Settings.b2_maxTranslationSquared)
  128. {
  129. float ratio = Settings.b2_maxTranslation / translation.Length();
  130. b._linearVelocity *= ratio;
  131. }
  132. float rotation = step.dt * b._angularVelocity;
  133. if (rotation * rotation > Settings.b2_maxRotationSquared)
  134. {
  135. float ratio = Settings.b2_maxRotation / Math.Abs(rotation);
  136. b._angularVelocity *= ratio;
  137. }
  138. // Store positions for continuous collision.
  139. b._sweep.c0 = b._sweep.c;
  140. b._sweep.a0 = b._sweep.a;
  141. // Integrate
  142. b._sweep.c += step.dt * b._linearVelocity;
  143. b._sweep.a += step.dt * b._angularVelocity;
  144. // Compute new transform
  145. b.SynchronizeTransform();
  146. // Note: shapes are synchronized later.
  147. }
  148. // Iterate over constraints.
  149. for (int i = 0; i < step.positionIterations; ++i)
  150. {
  151. bool contactsOkay = _contactSolver.SolvePositionConstraints(Settings.b2_contactBaumgarte);
  152. bool jointsOkay = true;
  153. for (int j = 0; j < _jointCount; ++j)
  154. {
  155. bool jointOkay = _joints[j].SolvePositionConstraints(Settings.b2_contactBaumgarte);
  156. jointsOkay = jointsOkay && jointOkay;
  157. }
  158. if (contactsOkay && jointsOkay)
  159. {
  160. // Exit early if the position errors are small.
  161. break;
  162. }
  163. }
  164. Report(_contactSolver._constraints);
  165. if (allowSleep)
  166. {
  167. float minSleepTime = Settings.b2_maxFloat;
  168. const float linTolSqr = Settings.b2_linearSleepTolerance * Settings.b2_linearSleepTolerance;
  169. const float angTolSqr = Settings.b2_angularSleepTolerance * Settings.b2_angularSleepTolerance;
  170. for (int i = 0; i < _bodyCount; ++i)
  171. {
  172. Body b = _bodies[i];
  173. if (b.GetType() == BodyType.Static)
  174. {
  175. continue;
  176. }
  177. if ((b._flags & BodyFlags.AutoSleep) == 0)
  178. {
  179. b._sleepTime = 0.0f;
  180. minSleepTime = 0.0f;
  181. }
  182. if ((b._flags & BodyFlags.AutoSleep) == 0 ||
  183. b._angularVelocity * b._angularVelocity > angTolSqr ||
  184. Vector2.Dot(b._linearVelocity, b._linearVelocity) > linTolSqr)
  185. {
  186. b._sleepTime = 0.0f;
  187. minSleepTime = 0.0f;
  188. }
  189. else
  190. {
  191. b._sleepTime += step.dt;
  192. minSleepTime = Math.Min(minSleepTime, b._sleepTime);
  193. }
  194. }
  195. if (minSleepTime >= Settings.b2_timeToSleep)
  196. {
  197. for (int i = 0; i < _bodyCount; ++i)
  198. {
  199. Body b = _bodies[i];
  200. b.SetAwake(false);
  201. }
  202. }
  203. }
  204. }
  205. public void Add(Body body)
  206. {
  207. Debug.Assert(_bodyCount < _bodyCapacity);
  208. body._islandIndex = _bodyCount;
  209. _bodies[_bodyCount++] = body;
  210. }
  211. public void Add(Contact contact)
  212. {
  213. Debug.Assert(_contactCount < _contactCapacity);
  214. _contacts[_contactCount++] = contact;
  215. }
  216. public void Add(Joint joint)
  217. {
  218. Debug.Assert(_jointCount < _jointCapacity);
  219. _joints[_jointCount++] = joint;
  220. }
  221. public void Report(ContactConstraint[] constraints)
  222. {
  223. if (_listener == null)
  224. {
  225. return;
  226. }
  227. for (int i = 0; i < _contactCount; ++i)
  228. {
  229. Contact c = _contacts[i];
  230. ContactConstraint cc = constraints[i];
  231. ContactImpulse impulse = new ContactImpulse();
  232. for (int j = 0; j < cc.pointCount; ++j)
  233. {
  234. impulse.normalImpulses[j] = cc.points[j].normalImpulse;
  235. impulse.tangentImpulses[j] = cc.points[j].tangentImpulse;
  236. }
  237. _listener.PostSolve(c, ref impulse);
  238. }
  239. }
  240. private ContactSolver _contactSolver = new ContactSolver();
  241. public IContactListener _listener;
  242. public Body[] _bodies;
  243. public Contact[] _contacts;
  244. public Joint[] _joints;
  245. public int _bodyCount;
  246. public int _contactCount;
  247. public int _jointCount;
  248. public int _bodyCapacity;
  249. public int _contactCapacity;
  250. public int _jointCapacity;
  251. public int _positionIterationCount;
  252. };
  253. }