Island.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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;
  26. using System.Diagnostics;
  27. using FarseerPhysics.Common;
  28. using FarseerPhysics.Dynamics.Contacts;
  29. using FarseerPhysics.Dynamics.Joints;
  30. using Microsoft.Xna.Framework;
  31. namespace FarseerPhysics.Dynamics
  32. {
  33. /// <summary>
  34. /// This is an internal class.
  35. /// </summary>
  36. public class Island
  37. {
  38. public Body[] Bodies;
  39. public int BodyCount;
  40. public int ContactCount;
  41. public int JointCount;
  42. private int _bodyCapacity;
  43. private int _contactCapacity;
  44. private ContactManager _contactManager;
  45. private ContactSolver _contactSolver = new ContactSolver();
  46. private Contact[] _contacts;
  47. private int _jointCapacity;
  48. private Joint[] _joints;
  49. public float JointUpdateTime;
  50. private const float LinTolSqr = Settings.LinearSleepTolerance * Settings.LinearSleepTolerance;
  51. private const float AngTolSqr = Settings.AngularSleepTolerance * Settings.AngularSleepTolerance;
  52. #if (!SILVERLIGHT)
  53. private Stopwatch _watch = new Stopwatch();
  54. #endif
  55. public void Reset(int bodyCapacity, int contactCapacity, int jointCapacity, ContactManager contactManager)
  56. {
  57. _bodyCapacity = bodyCapacity;
  58. _contactCapacity = contactCapacity;
  59. _jointCapacity = jointCapacity;
  60. BodyCount = 0;
  61. ContactCount = 0;
  62. JointCount = 0;
  63. _contactManager = contactManager;
  64. if (Bodies == null || Bodies.Length < bodyCapacity)
  65. {
  66. Bodies = new Body[bodyCapacity];
  67. }
  68. if (_contacts == null || _contacts.Length < contactCapacity)
  69. {
  70. _contacts = new Contact[contactCapacity * 2];
  71. }
  72. if (_joints == null || _joints.Length < jointCapacity)
  73. {
  74. _joints = new Joint[jointCapacity * 2];
  75. }
  76. }
  77. public void Clear()
  78. {
  79. BodyCount = 0;
  80. ContactCount = 0;
  81. JointCount = 0;
  82. }
  83. private float _tmpTime;
  84. public void Solve(ref TimeStep step, ref Vector2 gravity)
  85. {
  86. // Integrate velocities and apply damping.
  87. for (int i = 0; i < BodyCount; ++i)
  88. {
  89. Body b = Bodies[i];
  90. if (b.BodyType != BodyType.Dynamic)
  91. {
  92. continue;
  93. }
  94. // Integrate velocities.
  95. // FPE 3 only - Only apply gravity if the body wants it.
  96. if (b.IgnoreGravity)
  97. {
  98. b.LinearVelocityInternal.X += step.dt * (b.InvMass * b.Force.X);
  99. b.LinearVelocityInternal.Y += step.dt * (b.InvMass * b.Force.Y);
  100. b.AngularVelocityInternal += step.dt * b.InvI * b.Torque;
  101. }
  102. else
  103. {
  104. b.LinearVelocityInternal.X += step.dt * (gravity.X + b.InvMass * b.Force.X);
  105. b.LinearVelocityInternal.Y += step.dt * (gravity.Y + b.InvMass * b.Force.Y);
  106. b.AngularVelocityInternal += step.dt * b.InvI * b.Torque;
  107. }
  108. // Apply damping.
  109. // ODE: dv/dt + c * v = 0
  110. // Solution: v(t) = v0 * exp(-c * t)
  111. // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
  112. // v2 = exp(-c * dt) * v1
  113. // Taylor expansion:
  114. // v2 = (1.0f - c * dt) * v1
  115. b.LinearVelocityInternal *= MathUtils.Clamp(1.0f - step.dt * b.LinearDamping, 0.0f, 1.0f);
  116. b.AngularVelocityInternal *= MathUtils.Clamp(1.0f - step.dt * b.AngularDamping, 0.0f, 1.0f);
  117. }
  118. // Partition contacts so that contacts with static bodies are solved last.
  119. int i1 = -1;
  120. for (int i2 = 0; i2 < ContactCount; ++i2)
  121. {
  122. Fixture fixtureA = _contacts[i2].FixtureA;
  123. Fixture fixtureB = _contacts[i2].FixtureB;
  124. Body bodyA = fixtureA.Body;
  125. Body bodyB = fixtureB.Body;
  126. bool nonStatic = bodyA.BodyType != BodyType.Static && bodyB.BodyType != BodyType.Static;
  127. if (nonStatic)
  128. {
  129. ++i1;
  130. //TODO: Only swap if they are not the same? see http://code.google.com/p/box2d/issues/detail?id=162
  131. Contact tmp = _contacts[i1];
  132. _contacts[i1] = _contacts[i2];
  133. _contacts[i2] = tmp;
  134. }
  135. }
  136. // Initialize velocity constraints.
  137. _contactSolver.Reset(_contacts, ContactCount, step.dtRatio, Settings.EnableWarmstarting);
  138. _contactSolver.InitializeVelocityConstraints();
  139. if (Settings.EnableWarmstarting)
  140. {
  141. _contactSolver.WarmStart();
  142. }
  143. #if (!SILVERLIGHT)
  144. if (Settings.EnableDiagnostics)
  145. {
  146. _watch.Start();
  147. _tmpTime = 0;
  148. }
  149. #endif
  150. for (int i = 0; i < JointCount; ++i)
  151. {
  152. if (_joints[i].Enabled)
  153. _joints[i].InitVelocityConstraints(ref step);
  154. }
  155. #if (!SILVERLIGHT)
  156. if (Settings.EnableDiagnostics)
  157. {
  158. _tmpTime += _watch.ElapsedTicks;
  159. }
  160. #endif
  161. // Solve velocity constraints.
  162. for (int i = 0; i < Settings.VelocityIterations; ++i)
  163. {
  164. #if (!SILVERLIGHT)
  165. if (Settings.EnableDiagnostics)
  166. _watch.Start();
  167. #endif
  168. for (int j = 0; j < JointCount; ++j)
  169. {
  170. Joint joint = _joints[j];
  171. if (!joint.Enabled)
  172. continue;
  173. joint.SolveVelocityConstraints(ref step);
  174. joint.Validate(step.inv_dt);
  175. }
  176. #if (!SILVERLIGHT)
  177. if (Settings.EnableDiagnostics)
  178. {
  179. _watch.Stop();
  180. _tmpTime += _watch.ElapsedTicks;
  181. _watch.Reset();
  182. }
  183. #endif
  184. _contactSolver.SolveVelocityConstraints();
  185. }
  186. // Post-solve (store impulses for warm starting).
  187. _contactSolver.StoreImpulses();
  188. // Integrate positions.
  189. for (int i = 0; i < BodyCount; ++i)
  190. {
  191. Body b = Bodies[i];
  192. if (b.BodyType == BodyType.Static)
  193. {
  194. continue;
  195. }
  196. // Check for large velocities.
  197. float translationX = step.dt * b.LinearVelocityInternal.X;
  198. float translationY = step.dt * b.LinearVelocityInternal.Y;
  199. float result = translationX * translationX + translationY * translationY;
  200. if (result > Settings.MaxTranslationSquared)
  201. {
  202. float sq = (float)Math.Sqrt(result);
  203. float ratio = Settings.MaxTranslation / sq;
  204. b.LinearVelocityInternal.X *= ratio;
  205. b.LinearVelocityInternal.Y *= ratio;
  206. }
  207. float rotation = step.dt * b.AngularVelocityInternal;
  208. if (rotation * rotation > Settings.MaxRotationSquared)
  209. {
  210. float ratio = Settings.MaxRotation / Math.Abs(rotation);
  211. b.AngularVelocityInternal *= ratio;
  212. }
  213. // Store positions for continuous collision.
  214. b.Sweep.C0.X = b.Sweep.C.X;
  215. b.Sweep.C0.Y = b.Sweep.C.Y;
  216. b.Sweep.A0 = b.Sweep.A;
  217. // Integrate
  218. b.Sweep.C.X += step.dt * b.LinearVelocityInternal.X;
  219. b.Sweep.C.Y += step.dt * b.LinearVelocityInternal.Y;
  220. b.Sweep.A += step.dt * b.AngularVelocityInternal;
  221. // Compute new transform
  222. b.SynchronizeTransform();
  223. // Note: shapes are synchronized later.
  224. }
  225. // Iterate over constraints.
  226. for (int i = 0; i < Settings.PositionIterations; ++i)
  227. {
  228. bool contactsOkay = _contactSolver.SolvePositionConstraints(Settings.ContactBaumgarte);
  229. bool jointsOkay = true;
  230. #if (!SILVERLIGHT)
  231. if (Settings.EnableDiagnostics)
  232. _watch.Start();
  233. #endif
  234. for (int j = 0; j < JointCount; ++j)
  235. {
  236. Joint joint = _joints[j];
  237. if (!joint.Enabled)
  238. continue;
  239. bool jointOkay = joint.SolvePositionConstraints();
  240. jointsOkay = jointsOkay && jointOkay;
  241. }
  242. #if (!SILVERLIGHT)
  243. if (Settings.EnableDiagnostics)
  244. {
  245. _watch.Stop();
  246. _tmpTime += _watch.ElapsedTicks;
  247. _watch.Reset();
  248. }
  249. #endif
  250. if (contactsOkay && jointsOkay)
  251. {
  252. // Exit early if the position errors are small.
  253. break;
  254. }
  255. }
  256. #if (!SILVERLIGHT)
  257. if (Settings.EnableDiagnostics)
  258. {
  259. JointUpdateTime = _tmpTime;
  260. }
  261. #endif
  262. Report(_contactSolver.Constraints);
  263. if (Settings.AllowSleep)
  264. {
  265. float minSleepTime = Settings.MaxFloat;
  266. for (int i = 0; i < BodyCount; ++i)
  267. {
  268. Body b = Bodies[i];
  269. if (b.BodyType == BodyType.Static)
  270. {
  271. continue;
  272. }
  273. if ((b.Flags & BodyFlags.AutoSleep) == 0)
  274. {
  275. b.SleepTime = 0.0f;
  276. minSleepTime = 0.0f;
  277. }
  278. if ((b.Flags & BodyFlags.AutoSleep) == 0 ||
  279. b.AngularVelocityInternal * b.AngularVelocityInternal > AngTolSqr ||
  280. Vector2.Dot(b.LinearVelocityInternal, b.LinearVelocityInternal) > LinTolSqr)
  281. {
  282. b.SleepTime = 0.0f;
  283. minSleepTime = 0.0f;
  284. }
  285. else
  286. {
  287. b.SleepTime += step.dt;
  288. minSleepTime = Math.Min(minSleepTime, b.SleepTime);
  289. }
  290. }
  291. if (minSleepTime >= Settings.TimeToSleep)
  292. {
  293. for (int i = 0; i < BodyCount; ++i)
  294. {
  295. Body b = Bodies[i];
  296. b.Awake = false;
  297. }
  298. }
  299. }
  300. }
  301. internal void SolveTOI(ref TimeStep subStep)
  302. {
  303. _contactSolver.Reset(_contacts, ContactCount, subStep.dtRatio, false);
  304. // Solve position constraints.
  305. const float kTOIBaumgarte = 0.75f;
  306. for (int i = 0; i < Settings.TOIPositionIterations; ++i)
  307. {
  308. bool contactsOkay = _contactSolver.SolvePositionConstraints(kTOIBaumgarte);
  309. if (contactsOkay)
  310. {
  311. break;
  312. }
  313. if (i == Settings.TOIPositionIterations - 1)
  314. {
  315. i += 0;
  316. }
  317. }
  318. // Leap of faith to new safe state.
  319. for (int i = 0; i < BodyCount; ++i)
  320. {
  321. Body body = Bodies[i];
  322. body.Sweep.A0 = body.Sweep.A;
  323. body.Sweep.C0 = body.Sweep.C;
  324. }
  325. // No warm starting is needed for TOI events because warm
  326. // starting impulses were applied in the discrete solver.
  327. _contactSolver.InitializeVelocityConstraints();
  328. // Solve velocity constraints.
  329. for (int i = 0; i < Settings.TOIVelocityIterations; ++i)
  330. {
  331. _contactSolver.SolveVelocityConstraints();
  332. }
  333. // Don't store the TOI contact forces for warm starting
  334. // because they can be quite large.
  335. // Integrate positions.
  336. for (int i = 0; i < BodyCount; ++i)
  337. {
  338. Body b = Bodies[i];
  339. if (b.BodyType == BodyType.Static)
  340. {
  341. continue;
  342. }
  343. // Check for large velocities.
  344. float translationx = subStep.dt * b.LinearVelocityInternal.X;
  345. float translationy = subStep.dt * b.LinearVelocityInternal.Y;
  346. float dot = translationx * translationx + translationy * translationy;
  347. if (dot > Settings.MaxTranslationSquared)
  348. {
  349. float norm = 1f / (float)Math.Sqrt(dot);
  350. float value = Settings.MaxTranslation * subStep.inv_dt;
  351. b.LinearVelocityInternal.X = value * (translationx * norm);
  352. b.LinearVelocityInternal.Y = value * (translationy * norm);
  353. }
  354. float rotation = subStep.dt * b.AngularVelocity;
  355. if (rotation * rotation > Settings.MaxRotationSquared)
  356. {
  357. if (rotation < 0.0)
  358. {
  359. b.AngularVelocityInternal = -subStep.inv_dt * Settings.MaxRotation;
  360. }
  361. else
  362. {
  363. b.AngularVelocityInternal = subStep.inv_dt * Settings.MaxRotation;
  364. }
  365. }
  366. // Integrate
  367. b.Sweep.C.X += subStep.dt * b.LinearVelocityInternal.X;
  368. b.Sweep.C.Y += subStep.dt * b.LinearVelocityInternal.Y;
  369. b.Sweep.A += subStep.dt * b.AngularVelocityInternal;
  370. // Compute new transform
  371. b.SynchronizeTransform();
  372. // Note: shapes are synchronized later.
  373. }
  374. Report(_contactSolver.Constraints);
  375. }
  376. public void Add(Body body)
  377. {
  378. Debug.Assert(BodyCount < _bodyCapacity);
  379. Bodies[BodyCount++] = body;
  380. }
  381. public void Add(Contact contact)
  382. {
  383. Debug.Assert(ContactCount < _contactCapacity);
  384. _contacts[ContactCount++] = contact;
  385. }
  386. public void Add(Joint joint)
  387. {
  388. Debug.Assert(JointCount < _jointCapacity);
  389. _joints[JointCount++] = joint;
  390. }
  391. private void Report(ContactConstraint[] constraints)
  392. {
  393. if (_contactManager == null)
  394. return;
  395. for (int i = 0; i < ContactCount; ++i)
  396. {
  397. Contact c = _contacts[i];
  398. if (c.FixtureA.AfterCollision != null)
  399. c.FixtureA.AfterCollision(c.FixtureA, c.FixtureB, c);
  400. if (c.FixtureB.AfterCollision != null)
  401. c.FixtureB.AfterCollision(c.FixtureB, c.FixtureA, c);
  402. if (_contactManager.PostSolve != null)
  403. {
  404. ContactConstraint cc = constraints[i];
  405. _contactManager.PostSolve(c, cc);
  406. }
  407. }
  408. }
  409. }
  410. }