/PhysicsEngines/Farseer/FarseerBody.cs
C# | 618 lines | 401 code | 62 blank | 155 comment | 3 complexity | 3663254d62ecb841413f79b5f99682af MD5 | raw file
Possible License(s): Apache-2.0
- using System.Collections.Generic;
- using Delta.PhysicsEngines.Enums;
- using Delta.Utilities.Datatypes;
- using Delta.Utilities.Helpers;
- using FarseerPhysics.Common;
- using FarseerPhysics.Common.Decomposition;
- using FarseerPhysics.Dynamics;
- using FarseerPhysics.Dynamics.Contacts;
- using FarseerPhysics.Factories;
-
- namespace Delta.PhysicsEngines.Farseer
- {
- /// <summary>
- /// Farseer body implementation.
- /// </summary>
- internal class FarseerBody : PhysicsBody
- {
- #region Constants
- /// <summary>
- /// Default bounding box.
- /// </summary>
- private static readonly BoundingBox DefaultBoundingBox =
- new BoundingBox(Vector.Zero, Vector.One);
- #endregion
-
- #region Body (Public)
- /// <summary>
- /// Gets the Farseer native body (read-only).
- /// </summary>
- public Body Body
- {
- get
- {
- return farseerBody;
- }
- }
- #endregion
-
- #region Position (Public)
- /// <summary>
- /// Position given in world space.
- /// </summary>
- public override Vector Position
- {
- get
- {
- FarseerDatatypesMapping.Convert(farseerBody.Position, out position);
- return position * FarseerPhysics.InvScaleFactor;
- }
- set
- {
- farseerBody.Position = FarseerDatatypesMapping.Convert(ref value) *
- FarseerPhysics.ScaleFactor;
- }
- }
- #endregion
-
- #region Position2D (Public)
- /// <summary>
- /// Position 2D
- /// </summary>
- public override Point Position2D
- {
- get
- {
- var farseerVector2 = farseerBody.Position;
- return new Point(farseerVector2.X, farseerVector2.Y) *
- FarseerPhysics.InvScaleFactor;
- }
- set
- {
- farseerBody.Position = FarseerDatatypesMapping.Convert(ref value) *
- FarseerPhysics.ScaleFactor;
- }
- }
- #endregion
-
- #region Rotation (Public)
- /// <summary>
- /// Rotation angle in degrees for 2D bodies.
- /// </summary>
- public override float Rotation
- {
- get
- {
- return farseerBody.Rotation.RadiansToDegrees();
- }
- set
- {
- farseerBody.Rotation = value.DegreeToRadians();
- }
- }
- #endregion
-
- #region LinearVelocity (Public)
- /// <summary>
- /// The velocity of the body.
- /// </summary>
- /// <value>
- /// The linear velocity.
- /// </value>
- public override Vector LinearVelocity
- {
- get
- {
- FarseerDatatypesMapping.Convert(farseerBody.LinearVelocity,
- out linearVelocity);
- return linearVelocity;
- }
- set
- {
- farseerBody.LinearVelocity =
- FarseerDatatypesMapping.Convert(ref value);
- }
- }
- #endregion
-
- #region AngularVelocity (Public)
- /// <summary>
- /// Gets or Sets the angular velocity of the body.
- /// </summary>
- /// <remarks>
- /// For 2D physics simulation only X component is used.
- /// </remarks>
- public override Vector AngularVelocity
- {
- get
- {
- angularVelocity.X = farseerBody.AngularVelocity.RadiansToDegrees();
- return angularVelocity;
- }
- set
- {
- farseerBody.AngularVelocity = value.X.DegreeToRadians();
- }
- }
- #endregion
-
- #region AngularVelocity2D (Public)
- /// <summary>
- /// Angular velocity 2D as a float, for 2D only the .x component is used!
- /// </summary>
- public override float AngularVelocity2D
- {
- get
- {
- // Convert Farseers Radians into degrees as used by the engine
- return farseerBody.AngularVelocity.RadiansToDegrees();
- }
- set
- {
- // Convert to Farseers Radians
- farseerBody.AngularVelocity = value.DegreeToRadians();
- }
- }
- #endregion
-
- #region Mass (Public)
- /// <summary>
- /// Gets or sets the mass. Usually in kilograms (kg).
- /// </summary>
- public override float Mass
- {
- get
- {
- return base.Mass;
- }
- set
- {
- farseerBody.Mass = value;
- }
- }
- #endregion
-
- #region Restitution (Public)
- /// <summary>
- /// Gets the restitution of the body.
- /// </summary>
- public override float Restitution
- {
- get
- {
- return base.Restitution;
- }
- set
- {
- farseerBody.Restitution = value;
- base.Restitution = value;
- }
- }
- #endregion
-
- #region BoundingBox (Public)
- /// <summary>
- /// Gets the BoundingBox of the body.
- /// </summary>
- public override BoundingBox BoundingBox
- {
- get
- {
- // Zero bounding box
- return DefaultBoundingBox;
- }
- }
- #endregion
-
- #region Private
-
- #region farseerBody (Private)
- /// <summary>
- /// Farseer body.
- /// </summary>
- private readonly Body farseerBody;
- #endregion
-
- #region farseerFixtures (Private)
- /// <summary>
- /// List of Farseer fixtures.
- /// </summary>
- private List<Fixture> farseerFixtures;
- #endregion
-
- #region physicsManager (Private)
- /// <summary>
- /// Our Farseer physics implementation.
- /// </summary>
- private FarseerPhysics physicsManager;
- #endregion
-
- #region position (Private)
- private Vector position;
- #endregion
-
- #region linearVelocity (Private)
- private Vector linearVelocity;
- #endregion
-
- #region angularVelocity (Private)
- private Vector angularVelocity;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Initializes a new instance of the <see cref="FarseerBody"/> class.
- /// </summary>
- /// <param name="physicsManager">The physics manager.</param>
- /// <param name="shape">The shape.</param>
- /// <param name="initialPosition">Body initial position.</param>
- public FarseerBody(FarseerPhysics physicsManager,
- PhysicsShape shape, Vector initialPosition)
- : base(true, shape, initialPosition)
- {
- this.physicsManager = physicsManager;
- farseerFixtures = new List<Fixture>();
-
- // First create body.
- farseerBody = BodyFactory.CreateBody(physicsManager.farseerPhysicsWorld);
- farseerBody.Position =
- FarseerDatatypesMapping.Convert(ref initialPosition);
- farseerBody.Mass = base.mass;
- farseerBody.Restitution = base.restitution;
-
- // Now create shape.
- CreateShape();
-
- // Attach events
- Initialize();
-
- // By default is not static.
- SetIsStatic(false);
- }
- #endregion
-
- #region Dispose (Public)
- /// <summary>
- /// Handle disposing.
- /// </summary>
- public override void Dispose()
- {
- Remove();
- }
- #endregion
-
- #region ApplyForce (Public)
- /// <summary>
- /// Applies a force at the center of mass.
- /// </summary>
- /// <param name="force">
- /// Vector containing force data to apply to body in 3D space.
- /// </param>
- public override void ApplyForce(Vector force)
- {
- var farseerForce = FarseerDatatypesMapping.Convert(ref force);
- farseerBody.ApplyForce(ref farseerForce);
- }
-
- /// <summary>
- /// Apply a force at a world point. If the force is not
- /// applied at the center of mass, it will generate a torque and
- /// affect the angular velocity. This wakes up the body.
- /// </summary>
- /// <param name="force">
- /// Vector containing force data to apply to body in 3D space.
- /// </param>
- /// <param name="position">
- /// Relative position from where to apply force.
- /// </param>
- public override void ApplyForce(Vector force, Vector position)
- {
- var farseerForce = FarseerDatatypesMapping.Convert(ref force);
- var farseerPosition = FarseerDatatypesMapping.Convert(ref position);
- farseerBody.ApplyForce(ref farseerForce, ref farseerPosition);
- }
- #endregion
-
- #region ApplyTorque (Public)
- /// <summary>
- /// Apply a torque. This affects the angular velocity without affecting the
- /// linear velocity of the center of mass.
- /// </summary>
- /// <remarks>
- /// This wakes up the body.
- /// </remarks>
- /// <param name="torque">
- /// Vector containing torque data for both 2D and 3D shapes.
- /// </param>
- public override void ApplyTorque(Vector torque)
- {
- // For 2D stuff use only the X component.
- farseerBody.ApplyTorque(torque.X);
- }
- #endregion
-
- #region ApplyLinearImpulse (Public)
- /// <summary>
- /// Apply an impulse at a point. This immediately modifies the velocity.
- /// </summary>
- /// <remarks>
- /// This wakes up the body.
- /// </remarks>
- /// <param name="impulse">The impulse vector in 3D space.</param>
- public override void ApplyLinearImpulse(Vector impulse)
- {
- var farseerImpulse = FarseerDatatypesMapping.Convert(ref impulse) *
- FarseerPhysics.ScaleFactor;
- farseerBody.ApplyLinearImpulse(ref farseerImpulse);
- }
-
- /// <summary>
- /// Apply an impulse at a point. This immediately modifies the velocity.
- /// It also modifies the angular velocity if the point of application
- /// is not at the center of mass.
- /// </summary>
- /// <remarks>
- /// This wakes up the body.
- /// </remarks>
- /// <param name="impulse">The impulse vector in 3D space.</param>
- /// <param name="position">Relative position from where to apply.</param>
- public override void ApplyLinearImpulse(Vector impulse, Vector position)
- {
- var farseerImpulse =
- FarseerDatatypesMapping.Convert(ref impulse) *
- FarseerPhysics.ScaleFactor;
- var farseerPosition =
- FarseerDatatypesMapping.Convert(ref position);
-
- farseerBody.ApplyLinearImpulse(ref farseerImpulse, ref farseerPosition);
- }
- #endregion
-
- #region ApplyAngularImpulse (Public)
- public override void ApplyAngularImpulse(Vector impulse)
- {
- farseerBody.ApplyAngularImpulse(impulse.X);
- }
- #endregion
-
- #region Remove (Public)
- /// <summary>
- /// Remove
- /// </summary>
- public override void Remove()
- {
- farseerBody.OnCollision -= OnColliding;
- farseerBody.OnSeparation -= OnSeparation;
-
- base.Remove();
- }
- #endregion
-
- #region Methods (Private)
-
- #region CreateShape
- /// <summary>
- /// Creates shape from given properties.
- /// </summary>
- private void CreateShape()
- {
- float scaleFactor = FarseerPhysics.ScaleFactor;
-
- Dictionary<PhysicsShape.PropertyType, object> properties = Shape.Properties;
- Point tempPoint;
- switch (Shape.ShapeType)
- {
- // Circle
- case ShapeType.Circle:
- farseerFixtures.Add(FixtureFactory.AttachCircle(
- GetSafeFloat(properties, PhysicsShape.PropertyType.Radius) * scaleFactor,
- GetSafeFloat(properties, PhysicsShape.PropertyType.Density),
- farseerBody));
- break;
- // Rectangle
- case ShapeType.Rectangle:
- tempPoint = ArrayHelper.SafeGet<PhysicsShape.PropertyType, Point>(
- properties, PhysicsShape.PropertyType.Offset);
-
- farseerFixtures.Add(FixtureFactory.AttachRectangle(
- GetSafeFloat(properties, PhysicsShape.PropertyType.Width) * scaleFactor,
- GetSafeFloat(properties, PhysicsShape.PropertyType.Height) * scaleFactor,
- GetSafeFloat(properties, PhysicsShape.PropertyType.Density),
- FarseerDatatypesMapping.Convert(ref tempPoint),
- farseerBody));
- break;
-
- case ShapeType.Ellipse:
- farseerFixtures.Add(FixtureFactory.AttachEllipse(
- GetSafeFloat(properties, PhysicsShape.PropertyType.RadiusX) * scaleFactor,
- GetSafeFloat(properties, PhysicsShape.PropertyType.RadiusY) * scaleFactor,
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, int>(
- properties, PhysicsShape.PropertyType.Edges),
- GetSafeFloat(properties, PhysicsShape.PropertyType.Density),
- farseerBody));
- break;
-
- case ShapeType.Polygon:
- IList<Point> verticesList =
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, IList<Point>>(
- properties, PhysicsShape.PropertyType.Vertices);
-
- farseerFixtures.Add(FixtureFactory.AttachPolygon(
- new Vertices(FarseerDatatypesMapping.Convert(verticesList)),
- GetSafeFloat(properties, PhysicsShape.PropertyType.Density),
- farseerBody));
- break;
-
- case ShapeType.Compound:
- List<IList<Point>> verticesArrayList =
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, List<IList<Point>>>(
- properties, PhysicsShape.PropertyType.Vertices);
-
- farseerFixtures.Add(FixtureFactory.AttachCompoundPolygon(
- FarseerDatatypesMapping.Convert(verticesArrayList),
- GetSafeFloat(properties, PhysicsShape.PropertyType.Density),
- farseerBody));
- break;
-
- case ShapeType.Gear:
- farseerFixtures = CreateGear(
- GetSafeFloat(properties, PhysicsShape.PropertyType.Radius) * scaleFactor,
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, int>(
- properties, PhysicsShape.PropertyType.NumberOfTeeth),
- GetSafeFloat(properties, PhysicsShape.PropertyType.TipPercentage),
- GetSafeFloat(properties, PhysicsShape.PropertyType.ToothHeight) *
- scaleFactor,
- GetSafeFloat(properties, PhysicsShape.PropertyType.Density),
- farseerBody);
- break;
- }
-
- // Initialize Tag for later retrieve
- foreach (Fixture fixture in farseerFixtures)
- {
- fixture.UserData = this;
- }
- }
- #endregion
-
- #region GetSafeFloat
- /// <summary>
- /// Private helper method to get a float value from the properties.
- /// </summary>
- /// <param name="properties">Shape properties.</param>
- /// <param name="type">Property type to get.</param>
- /// <returns>Float value from the properties.</returns>
- private static float GetSafeFloat(
- Dictionary<PhysicsShape.PropertyType, object> properties,
- PhysicsShape.PropertyType type)
- {
- return ArrayHelper.SafeGet<PhysicsShape.PropertyType, float>(properties, type);
- }
- #endregion
-
- #region CreateGear
- /// <summary>
- /// Helper method for creating gear fixture list.
- /// </summary>
- /// <param name="radius">The radius.</param>
- /// <param name="numberOfTeeth">The number of teeth.</param>
- /// <param name="tipPercentage">The tip percentage.</param>
- /// <param name="toothHeight">Height of the tooth.</param>
- /// <param name="density">The density.</param>
- /// <param name="body">The body.</param>
- /// <returns>List containing all fixtures used for Gear shape.</returns>
- private static List<Fixture> CreateGear(float radius, int numberOfTeeth,
- float tipPercentage, float toothHeight, float density, Body body)
- {
- Vertices gearPolygon = PolygonTools.CreateGear(radius, numberOfTeeth,
- tipPercentage, toothHeight);
-
- //Gears can in some cases be convex
- if (gearPolygon.IsConvex() == false)
- {
- //Decompose the gear:
- List<Vertices> list = EarclipDecomposer.ConvexPartition(gearPolygon);
-
- return FixtureFactory.AttachCompoundPolygon(list, density, body,
- null);
- }
-
- List<Fixture> fixtures = new List<Fixture>();
- fixtures.Add(FixtureFactory.AttachPolygon(gearPolygon, density, body,
- null));
- return fixtures;
- }
- #endregion
-
- #region OnColliding
- /// <summary>
- /// On colliding farseeer handle event.
- /// </summary>
- /// <param name="fixtureA">Farseer fixture A.</param>
- /// <param name="fixtureB">Farseer fixture B.</param>
- /// <param name="contacts">Farseer contact data.</param>
- /// <returns>True to response on farseer collision event.</returns>
- private bool OnColliding(Fixture fixtureA, Fixture fixtureB, Contact contacts)
- {
- PhysicsBody other = (PhysicsBody)fixtureB.UserData;
-
- // Fire event
- OnCollisionBegin(other);
-
- return true;
- }
- #endregion
-
- #region OnSeparation
- private void OnSeparation(Fixture fixtureA, Fixture fixtureB)
- {
- PhysicsBody other = (PhysicsBody)fixtureB.UserData;
-
- // Fire event
- OnCollisionEnd(other);
- }
- #endregion
-
- #region Initialize
- /// <summary>
- /// Initialize
- /// </summary>
- protected void Initialize()
- {
- farseerBody.OnCollision += OnColliding;
- farseerBody.OnSeparation += OnSeparation;
- }
- #endregion
-
- #region SetIsStatic
- protected override void SetIsStatic(bool value)
- {
- farseerBody.IsStatic = value;
-
- farseerBody.BodyType = value
- ? BodyType.Static
- : BodyType.Dynamic;
- }
- #endregion
-
- #region SetIsActive
- protected override void SetIsActive(bool value)
- {
- farseerBody.Enabled = value;
- }
- #endregion
-
- #region SetFriction
- protected override void SetFriction(float value)
- {
- foreach (Fixture fixture in farseerBody.FixtureList)
- {
- fixture.Friction = value;
- }
- }
- #endregion
-
- #region GetDebugInfo
- /// <summary>
- /// Return optional debug information text with details about this body!
- /// </summary>
- /// <returns>Extra information about inertia, flags, etc.</returns>
- public override string GetDebugInfo()
- {
- return "FarseerBody: " +
- "IsBullet=" + farseerBody.IsBullet +
- ", Inertia=" + farseerBody.Inertia +
- ", Mass=" + farseerBody.Mass +
- ", LinearVelocity=" + farseerBody.LinearVelocity +
- ", LinearDamping=" + farseerBody.LinearDamping +
- ", IgnoreGravity=" + farseerBody.IgnoreGravity +
- ", Revolutions=" + farseerBody.Revolutions +
- ", Time.Delta=" + Delta.Engine.Time.Delta;
- }
- #endregion
-
- #endregion
- }
- }