/PhysicsEngines/Farseer/FarseerPhysics.cs
C# | 403 lines | 259 code | 39 blank | 105 comment | 17 complexity | d5c595fb08a7404453c52f85a03fd2ab MD5 | raw file
Possible License(s): Apache-2.0
- using Delta.PhysicsEngines.Enums;
- using Delta.Utilities;
- using Delta.Utilities.Datatypes;
- using FarseerPhysics;
- using FarseerPhysics.Dynamics;
- using Microsoft.Xna.Framework;
- using NUnit.Framework;
-
- namespace Delta.PhysicsEngines.Farseer
- {
- /// <summary>
- /// Farseer3 physics manager for 2D physics
- /// </summary>
- public class FarseerPhysics : Physics
- {
- #region Constants
- /// <summary>
- /// Scale factor used for precision between DeltaEngine draw system and
- /// Farseer. This is important because Farseer thinks in pixels and the
- /// quadratic space between 0 and 1 is not enough precision for most
- /// Farseer operations. The ScaleFactor helps to scale quadratic space
- /// up to 1000 units for Farseer and to make all methods work correctly.
- /// </summary>
- internal const float ScaleFactor = 1000.0f;
-
- /// <summary>
- /// Inverse of ScaleFactor (1.0f / ScaleFactor)
- /// </summary>
- internal const float InvScaleFactor = 1.0f / ScaleFactor;
- #endregion
-
- #region Internal
-
- #region farseerPhysicsWorld (Internal)
- /// <summary>
- /// Farseer Physic World.
- /// </summary>
- internal World farseerPhysicsWorld;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Constructor
- /// </summary>
- public FarseerPhysics()
- : base(true, "Farseer")
- {
- // Create a new physics world, with zero gravity.
- // The gravity can set later.
- farseerPhysicsWorld = new World(Vector2.Zero);
-
- // No CCD physics.
- Settings.ContinuousPhysics = false;
- }
- #endregion
-
- #region IsShapeSupported (Public)
- /// <summary>
- /// Gets whether the current physics module supports given shape type.
- /// </summary>
- /// <param name="shapeType">Type of the shape.</param>
- /// <returns>
- /// <c>true</c> if [is shape supported] [the specified shape type]; otherwise, <c>false</c>.
- /// </returns>
- public override bool IsShapeSupported(ShapeType shapeType)
- {
- switch (shapeType)
- {
- case ShapeType.Circle:
- case ShapeType.Ellipse:
- case ShapeType.Rectangle:
- case ShapeType.Polygon:
- case ShapeType.Compound:
- case ShapeType.Gear:
- return true;
- }
-
- return false;
- }
- #endregion
-
- #region IsJointSupported (Public)
- /// <summary>
- /// Gets whether the current physics module supports given joint type.
- /// </summary>
- /// <param name="shapeType">Type of the shape.</param>
- /// <returns>
- /// <c>true</c> if [is joint supported] [the specified shape type]; otherwise, <c>false</c>.
- /// </returns>
- public override bool IsJointSupported(JointType shapeType)
- {
- switch (shapeType)
- {
- case JointType.Angle:
- case JointType.Prismatic:
- case JointType.PointPointDistance:
- return true;
- }
-
- return false;
- }
- #endregion
-
- #region IsFeatureSupported (Public)
- /// <summary>
- /// Gets whether the current physics module supports given feature.
- /// </summary>
- /// <param name="support">The support.</param>
- /// <returns>
- /// <c>true</c> if the specific feature is supported, <c>false</c> otherwise.
- /// </returns>
- public override bool IsFeatureSupported(FeatureSupport support)
- {
- switch (support)
- {
- case FeatureSupport.Joint:
- return true;
- }
-
- return false;
- }
- #endregion
-
- #region SetGroundPlane (Public)
- /// <summary>
- /// Implementation of SetGroundPlane
- /// </summary>
- /// <param name="enable">True to enable, false otherwise.</param>
- /// <param name="height">The height of the plane.</param>
- public override void SetGroundPlane(bool enable, float height)
- {
- }
- #endregion
-
- #region Methods (Private)
-
- #region CreateBody
- protected override PhysicsBody CreateBody(bool is2D,
- PhysicsShape shape, Vector initialPosition)
- {
- if (is2D == false)
- {
- Log.Warning("Farseer does not support 3D bodies.");
- return null;
- }
-
- FarseerBody body = new FarseerBody(this, shape, initialPosition);
- bodies.Add(body);
- return body;
- }
- #endregion
-
- #region CreateJoint
- public override PhysicsJoint CreateJoint(
- JointType jointType,
- PhysicsBody bodyA,
- PhysicsBody bodyB,
- object[] args)
- {
- if (IsJointSupported(jointType) == false)
- {
- Log.Warning("Current module does not support " +
- "the type of joint " + jointType);
- return null;
- }
-
- PhysicsJoint joint = new FarseerJoint(this, jointType, bodyA, bodyB, args);
- if (joint != null)
- {
- joints.Add(joint);
- }
- return joint;
- }
- #endregion
-
- #region RemoveBodyImpl
- protected override void RemoveBodyImpl(PhysicsBody body)
- {
- // Remove body from farseer world
- farseerPhysicsWorld.RemoveBody(
- (body as FarseerBody).Body
- );
- }
- #endregion
-
- #region RemoveJointImpl
- protected override void RemoveJointImpl(PhysicsJoint joint)
- {
- // Remove body from farseer world
- farseerPhysicsWorld.RemoveJoint(
- (joint as FarseerJoint).Joint
- );
- }
- #endregion
-
- #region RayCastImpl
- /// <summary>
- /// Rays the cast impl.
- /// </summary>
- /// <param name="ray">The ray.</param>
- /// <param name="foundBody">The found body.</param>
- /// <param name="surfaceNormal">The surface normal.</param>
- /// <param name="fraction">The fraction.</param>
- /// <param name="userData">The user data.</param>
- /// <param name="checkGround">Whether to perform ray cast on 2D ground too.</param>
- /// <returns>True if any intersection happen, false otherwise.</returns>
- protected override bool RayCastImpl(Ray ray, bool checkGround,
- out PhysicsBody foundBody, out Vector surfaceNormal, out float fraction,
- out object userData)
- {
- foundBody = null;
- fraction = 0.0f;
- surfaceNormal = Vector.Zero;
- userData = null;
- Log.Warning(
- @"Farseer physics does not perform 3D ray cast...Please use
- FindRayCast2D");
- return false;
- }
- #endregion
-
- #region RayCastImpl2D
- /// <summary>
- /// Rays the cast impl 2D.
- /// </summary>
- /// <param name="point1">The point1.</param>
- /// <param name="point2">The point2.</param>
- /// <param name="outBody">The out body.</param>
- /// <param name="normal">The normal.</param>
- /// <param name="fraction">The fraction.</param>
- /// <returns>True if any intersection was found.</returns>
- protected override bool RayCastImpl2D(Point point1, Point point2,
- out PhysicsBody outBody, out Point normal, out float fraction)
- {
- PhysicsBody foundBody = null;
- Point foundNormal = Point.Zero;
- float foundFraction = 0.0f;
- bool result = false;
- farseerPhysicsWorld.RayCast((fixture, p, n, fr) =>
- {
- foundBody = FindBodyByFixture(fixture);
- FarseerDatatypesMapping.Convert(ref n, out foundNormal);
- foundNormal *= InvScaleFactor;
- foundFraction = fr;
- result = true;
- return 1;
- },
- FarseerDatatypesMapping.Convert(ref point1) * ScaleFactor,
- FarseerDatatypesMapping.Convert(ref point2) * ScaleFactor);
-
- outBody = foundBody;
- normal = foundNormal;
- fraction = foundFraction;
- return result;
- }
- #endregion
-
- #region SetGravity
- protected override void SetGravity(Vector gravity)
- {
- var valueToSet = FarseerDatatypesMapping.Convert(ref gravity) *
- ScaleFactor;
- farseerPhysicsWorld.Gravity = valueToSet;
- }
- #endregion
-
- #region GetTotalPhysicsTime
- protected override double GetTotalPhysicsTime()
- {
- return farseerPhysicsWorld.UpdateTime;
- }
- #endregion
-
- #region SetMultithreading
- protected override void SetMultithreading(bool enable)
- {
- // Not supported
- if (enable)
- {
- Log.Warning("Farseer does not support multi-threading yet!");
- }
- }
- #endregion
-
- #region UpdateSimulation
- /// <summary>
- /// Perform Farseer simulation step.
- /// </summary>
- protected override void UpdateSimulation(float timeStep)
- {
- // Update profiling update time also
- profilingInfo.UpdateTime = farseerPhysicsWorld.UpdateTime;
-
- if (IsPaused == false)
- {
- farseerPhysicsWorld.Step(timeStep);
- //if (Delta.Engine.Time.CheckEvery(1.0f / 30.0f))
- //{
- // farseerPhysicsWorld.Step(1.0f / 30.0f);
- //}
- }
- }
- #endregion
-
- #region FindBodyByFixture
- /// <summary>
- /// Find a farseer object by body.
- /// </summary>
- /// <param name="fixtureToFind">Farseer fixture to search for.</param>
- /// <returns>Farseer physics body or null if not found.</returns>
- internal FarseerBody FindBodyByFixture(Fixture fixtureToFind)
- {
- // Iterate through all farseer objects.
- for (int index = 0; index < bodies.Count; index++)
- {
- FarseerBody farseerBody = bodies[index] as FarseerBody;
-
- // Now iterate fixture of Farseer body
- if (farseerBody == null)
- {
- continue;
- }
-
- // Iterate again for Farseer fixture
- foreach (Fixture iter in farseerBody.Body.FixtureList)
- {
- // If we find the right fixture, return the object.
- if (iter == fixtureToFind)
- {
- return farseerBody;
- }
- }
- }
- return null;
- }
- #endregion
-
- #endregion
-
- /// <summary>
- /// Tests
- /// </summary>
- internal class FarseerPhysicsTests
- {
- #region TestInitialization (Static)
- /// <summary>
- /// Test whether initialization has been done.
- /// </summary>
- [Test]
- public static void TestInitialization()
- {
- // check that everything has been OK with Physics initiallization
- Assert.NotNull(Bodies);
- }
- #endregion
-
- #region TestCreate2DBodyWithShape (Static)
- /// <summary>
- /// Test creation of 2D body with shape.
- /// </summary>
- [Test]
- public static void TestCreate2DBodyWithShape()
- {
- PhysicsBody body = CreateCircle(2.0f, 1.0f);
- Assert.NotNull(body);
- Assert.NotNull(body.Shape);
- }
- #endregion
-
- #region TestFeatureSupport (Static)
- /// <summary>
- /// Test whether given feature is supoorted.
- /// </summary>
- [Test]
- public static void TestFeatureSupport()
- {
- // Farseer should support joint.
- bool isSupported = Instance.IsFeatureSupported(
- FeatureSupport.Joint);
-
- Assert.True(isSupported);
- }
- #endregion
-
- #region TestShapeSupport (Static)
- /// <summary>
- /// Test whether given shape is supoorted.
- /// </summary>
- [Test]
- public static void TestShapeSupport()
- {
- // farseer support circle shape.
- bool isSupported = Instance.IsShapeSupported(
- ShapeType.Circle);
-
- Assert.True(isSupported);
- }
- #endregion
- }
- }
- }