PathManager.cs 10 KB

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