PathManager.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using System;
  2. using System.Collections.Generic;
  3. using FarseerPhysics.Collision.Shapes;
  4. using FarseerPhysics.Common;
  5. using FarseerPhysics.Common.Decomposition;
  6. using FarseerPhysics.Dynamics;
  7. using FarseerPhysics.Dynamics.Joints;
  8. using Microsoft.Xna.Framework;
  9. namespace FarseerPhysics.Factories
  10. {
  11. /// <summary>
  12. /// An easy to use manager for creating paths.
  13. /// </summary>
  14. public static class PathManager
  15. {
  16. public enum LinkType
  17. {
  18. Revolute,
  19. Slider
  20. }
  21. //Contributed by Matthew Bettcher
  22. /// <summary>
  23. /// Convert a path into a set of edges and attaches them to the specified body.
  24. /// Note: use only for static edges.
  25. /// </summary>
  26. /// <param name="path">The path.</param>
  27. /// <param name="body">The body.</param>
  28. /// <param name="subdivisions">The subdivisions.</param>
  29. public static void ConvertPathToEdges(Path path, Body body, int subdivisions)
  30. {
  31. Vertices verts = path.GetVertices(subdivisions);
  32. if (path.Closed)
  33. {
  34. LoopShape loop = new LoopShape(verts);
  35. body.CreateFixture(loop);
  36. }
  37. else
  38. {
  39. for (int i = 1; i < verts.Count; i++)
  40. {
  41. body.CreateFixture(new EdgeShape(verts[i], verts[i - 1]));
  42. }
  43. }
  44. }
  45. /// <summary>
  46. /// Convert a closed path into a polygon.
  47. /// Convex decomposition is automatically performed.
  48. /// </summary>
  49. /// <param name="path">The path.</param>
  50. /// <param name="body">The body.</param>
  51. /// <param name="density">The density.</param>
  52. /// <param name="subdivisions">The subdivisions.</param>
  53. public static void ConvertPathToPolygon(Path path, Body body, float density, int subdivisions)
  54. {
  55. if (!path.Closed)
  56. throw new Exception("The path must be closed to convert to a polygon.");
  57. List<Vector2> verts = path.GetVertices(subdivisions);
  58. List<Vertices> decomposedVerts = EarclipDecomposer.ConvexPartition(new Vertices(verts));
  59. //List<Vertices> decomposedVerts = BayazitDecomposer.ConvexPartition(new Vertices(verts));
  60. foreach (Vertices item in decomposedVerts)
  61. {
  62. body.CreateFixture(new PolygonShape(item, density));
  63. }
  64. }
  65. /// <summary>
  66. /// Duplicates the given Body along the given path for approximatly the given copies.
  67. /// </summary>
  68. /// <param name="world">The world.</param>
  69. /// <param name="path">The path.</param>
  70. /// <param name="shapes">The shapes.</param>
  71. /// <param name="type">The type.</param>
  72. /// <param name="copies">The copies.</param>
  73. /// <param name="userData"></param>
  74. /// <returns></returns>
  75. public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, IEnumerable<Shape> shapes,
  76. BodyType type, int copies, object userData)
  77. {
  78. List<Vector3> centers = path.SubdivideEvenly(copies);
  79. List<Body> bodyList = new List<Body>();
  80. for (int i = 0; i < centers.Count; i++)
  81. {
  82. Body b = new Body(world);
  83. // copy the type from original body
  84. b.BodyType = type;
  85. b.Position = new Vector2(centers[i].X, centers[i].Y);
  86. b.Rotation = centers[i].Z;
  87. foreach (Shape shape in shapes)
  88. {
  89. b.CreateFixture(shape, userData);
  90. }
  91. bodyList.Add(b);
  92. }
  93. return bodyList;
  94. }
  95. public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, IEnumerable<Shape> shapes,
  96. BodyType type, int copies)
  97. {
  98. return EvenlyDistributeShapesAlongPath(world, path, shapes, type, copies, null);
  99. }
  100. /// <summary>
  101. /// Duplicates the given Body along the given path for approximatly the given copies.
  102. /// </summary>
  103. /// <param name="world">The world.</param>
  104. /// <param name="path">The path.</param>
  105. /// <param name="shape">The shape.</param>
  106. /// <param name="type">The type.</param>
  107. /// <param name="copies">The copies.</param>
  108. /// <param name="userData">The user data.</param>
  109. /// <returns></returns>
  110. public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type,
  111. int copies, object userData)
  112. {
  113. List<Shape> shapes = new List<Shape>(1);
  114. shapes.Add(shape);
  115. return EvenlyDistributeShapesAlongPath(world, path, shapes, type, copies, userData);
  116. }
  117. public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type,
  118. int copies)
  119. {
  120. return EvenlyDistributeShapesAlongPath(world, path, shape, type, copies, null);
  121. }
  122. //TODO: Comment better
  123. /// <summary>
  124. /// Moves the body on the path.
  125. /// </summary>
  126. /// <param name="path">The path.</param>
  127. /// <param name="body">The body.</param>
  128. /// <param name="time">The time.</param>
  129. /// <param name="strength">The strength.</param>
  130. /// <param name="timeStep">The time step.</param>
  131. public static void MoveBodyOnPath(Path path, Body body, float time, float strength, float timeStep)
  132. {
  133. Vector2 destination = path.GetPosition(time);
  134. Vector2 positionDelta = body.Position - destination;
  135. Vector2 velocity = (positionDelta / timeStep) * strength;
  136. body.LinearVelocity = -velocity;
  137. }
  138. /// <summary>
  139. /// Attaches the bodies with revolute joints.
  140. /// </summary>
  141. /// <param name="world">The world.</param>
  142. /// <param name="bodies">The bodies.</param>
  143. /// <param name="localAnchorA">The local anchor A.</param>
  144. /// <param name="localAnchorB">The local anchor B.</param>
  145. /// <param name="connectFirstAndLast">if set to <c>true</c> [connect first and last].</param>
  146. /// <param name="collideConnected">if set to <c>true</c> [collide connected].</param>
  147. public static List<RevoluteJoint> AttachBodiesWithRevoluteJoint(World world, List<Body> bodies,
  148. Vector2 localAnchorA,
  149. Vector2 localAnchorB, bool connectFirstAndLast,
  150. bool collideConnected)
  151. {
  152. List<RevoluteJoint> joints = new List<RevoluteJoint>(bodies.Count + 1);
  153. for (int i = 1; i < bodies.Count; i++)
  154. {
  155. RevoluteJoint joint = new RevoluteJoint(bodies[i], bodies[i - 1], localAnchorA, localAnchorB);
  156. joint.CollideConnected = collideConnected;
  157. world.AddJoint(joint);
  158. joints.Add(joint);
  159. }
  160. if (connectFirstAndLast)
  161. {
  162. RevoluteJoint lastjoint = new RevoluteJoint(bodies[0], bodies[bodies.Count - 1], localAnchorA,
  163. localAnchorB);
  164. lastjoint.CollideConnected = collideConnected;
  165. world.AddJoint(lastjoint);
  166. joints.Add(lastjoint);
  167. }
  168. return joints;
  169. }
  170. /// <summary>
  171. /// Attaches the bodies with revolute joints.
  172. /// </summary>
  173. /// <param name="world">The world.</param>
  174. /// <param name="bodies">The bodies.</param>
  175. /// <param name="localAnchorA">The local anchor A.</param>
  176. /// <param name="localAnchorB">The local anchor B.</param>
  177. /// <param name="connectFirstAndLast">if set to <c>true</c> [connect first and last].</param>
  178. /// <param name="collideConnected">if set to <c>true</c> [collide connected].</param>
  179. /// <param name="minLength">Minimum length of the slider joint.</param>
  180. /// <param name="maxLength">Maximum length of the slider joint.</param>
  181. /// <returns></returns>
  182. public static List<SliderJoint> AttachBodiesWithSliderJoint(World world, List<Body> bodies, Vector2 localAnchorA,
  183. Vector2 localAnchorB, bool connectFirstAndLast,
  184. bool collideConnected, float minLength,
  185. float maxLength)
  186. {
  187. List<SliderJoint> joints = new List<SliderJoint>(bodies.Count + 1);
  188. for (int i = 1; i < bodies.Count; i++)
  189. {
  190. SliderJoint joint = new SliderJoint(bodies[i], bodies[i - 1], localAnchorA, localAnchorB, minLength,
  191. maxLength);
  192. joint.CollideConnected = collideConnected;
  193. world.AddJoint(joint);
  194. joints.Add(joint);
  195. }
  196. if (connectFirstAndLast)
  197. {
  198. SliderJoint lastjoint = new SliderJoint(bodies[0], bodies[bodies.Count - 1], localAnchorA, localAnchorB,
  199. minLength, maxLength);
  200. lastjoint.CollideConnected = collideConnected;
  201. world.AddJoint(lastjoint);
  202. joints.Add(lastjoint);
  203. }
  204. return joints;
  205. }
  206. }
  207. }