using System; using System.Collections.Generic; using FarseerPhysics.Collision.Shapes; using FarseerPhysics.Common; using FarseerPhysics.Common.Decomposition; using FarseerPhysics.Dynamics; using FarseerPhysics.Dynamics.Joints; using Microsoft.Xna.Framework; namespace FarseerPhysics.Factories { /// /// An easy to use manager for creating paths. /// public static class PathManager { #region LinkType enum public enum LinkType { Revolute, Slider } #endregion //Contributed by Matthew Bettcher /// /// Convert a path into a set of edges and attaches them to the specified body. /// Note: use only for static edges. /// /// The path. /// The body. /// The subdivisions. public static void ConvertPathToEdges(Path path, Body body, int subdivisions) { Vertices verts = path.GetVertices(subdivisions); if (path.Closed) { LoopShape loop = new LoopShape(verts); body.CreateFixture(loop); } else { for (int i = 1; i < verts.Count; i++) { body.CreateFixture(new EdgeShape(verts[i], verts[i - 1])); } } } /// /// Convert a closed path into a polygon. /// Convex decomposition is automatically performed. /// /// The path. /// The body. /// The density. /// The subdivisions. public static void ConvertPathToPolygon(Path path, Body body, float density, int subdivisions) { if (!path.Closed) throw new Exception("The path must be closed to convert to a polygon."); List verts = path.GetVertices(subdivisions); List decomposedVerts = EarclipDecomposer.ConvexPartition(new Vertices(verts)); //List decomposedVerts = BayazitDecomposer.ConvexPartition(new Vertices(verts)); foreach (Vertices item in decomposedVerts) { body.CreateFixture(new PolygonShape(item, density)); } } /// /// Duplicates the given Body along the given path for approximatly the given copies. /// /// The world. /// The path. /// The shapes. /// The type. /// The copies. /// /// public static List EvenlyDistributeShapesAlongPath(World world, Path path, IEnumerable shapes, BodyType type, int copies, object userData) { List centers = path.SubdivideEvenly(copies); List bodyList = new List(); for (int i = 0; i < centers.Count; i++) { Body b = new Body(world); // copy the type from original body b.BodyType = type; b.Position = new Vector2(centers[i].X, centers[i].Y); b.Rotation = centers[i].Z; foreach (Shape shape in shapes) { b.CreateFixture(shape, userData); } bodyList.Add(b); } return bodyList; } public static List EvenlyDistributeShapesAlongPath(World world, Path path, IEnumerable shapes, BodyType type, int copies) { return EvenlyDistributeShapesAlongPath(world, path, shapes, type, copies, null); } /// /// Duplicates the given Body along the given path for approximatly the given copies. /// /// The world. /// The path. /// The shape. /// The type. /// The copies. /// The user data. /// public static List EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type, int copies, object userData) { List shapes = new List(1); shapes.Add(shape); return EvenlyDistributeShapesAlongPath(world, path, shapes, type, copies, userData); } public static List EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type, int copies) { return EvenlyDistributeShapesAlongPath(world, path, shape, type, copies, null); } //TODO: Comment better /// /// Moves the body on the path. /// /// The path. /// The body. /// The time. /// The strength. /// The time step. public static void MoveBodyOnPath(Path path, Body body, float time, float strength, float timeStep) { Vector2 destination = path.GetPosition(time); Vector2 positionDelta = body.Position - destination; Vector2 velocity = (positionDelta / timeStep) * strength; body.LinearVelocity = -velocity; } /// /// Attaches the bodies with revolute joints. /// /// The world. /// The bodies. /// The local anchor A. /// The local anchor B. /// if set to true [connect first and last]. /// if set to true [collide connected]. public static List AttachBodiesWithRevoluteJoint(World world, List bodies, Vector2 localAnchorA, Vector2 localAnchorB, bool connectFirstAndLast, bool collideConnected) { List joints = new List(bodies.Count + 1); for (int i = 1; i < bodies.Count; i++) { RevoluteJoint joint = new RevoluteJoint(bodies[i], bodies[i - 1], localAnchorA, localAnchorB); joint.CollideConnected = collideConnected; world.AddJoint(joint); joints.Add(joint); } if (connectFirstAndLast) { RevoluteJoint lastjoint = new RevoluteJoint(bodies[0], bodies[bodies.Count - 1], localAnchorA, localAnchorB); lastjoint.CollideConnected = collideConnected; world.AddJoint(lastjoint); joints.Add(lastjoint); } return joints; } /// /// Attaches the bodies with revolute joints. /// /// The world. /// The bodies. /// The local anchor A. /// The local anchor B. /// if set to true [connect first and last]. /// if set to true [collide connected]. /// Minimum length of the slider joint. /// Maximum length of the slider joint. /// public static List AttachBodiesWithSliderJoint(World world, List bodies, Vector2 localAnchorA, Vector2 localAnchorB, bool connectFirstAndLast, bool collideConnected, float minLength, float maxLength) { List joints = new List(bodies.Count + 1); for (int i = 1; i < bodies.Count; i++) { SliderJoint joint = new SliderJoint(bodies[i], bodies[i - 1], localAnchorA, localAnchorB, minLength, maxLength); joint.CollideConnected = collideConnected; world.AddJoint(joint); joints.Add(joint); } if (connectFirstAndLast) { SliderJoint lastjoint = new SliderJoint(bodies[0], bodies[bodies.Count - 1], localAnchorA, localAnchorB, minLength, maxLength); lastjoint.CollideConnected = collideConnected; world.AddJoint(lastjoint); joints.Add(lastjoint); } return joints; } } }