PageRenderTime 124ms CodeModel.GetById 80ms app.highlight 13ms RepoModel.GetById 17ms app.codeStats 0ms

/PhysicsEngines/Farseer/FarseerPhysics.cs

#
C# | 403 lines | 259 code | 39 blank | 105 comment | 17 complexity | d5c595fb08a7404453c52f85a03fd2ab MD5 | raw file
  1using Delta.PhysicsEngines.Enums;
  2using Delta.Utilities;
  3using Delta.Utilities.Datatypes;
  4using FarseerPhysics;
  5using FarseerPhysics.Dynamics;
  6using Microsoft.Xna.Framework;
  7using NUnit.Framework;
  8
  9namespace Delta.PhysicsEngines.Farseer
 10{
 11	/// <summary>
 12	/// Farseer3 physics manager for 2D physics
 13	/// </summary>
 14	public class FarseerPhysics : Physics
 15	{
 16		#region Constants
 17		/// <summary>
 18		/// Scale factor used for precision between DeltaEngine draw system and
 19		/// Farseer. This is important because Farseer thinks in pixels and the
 20		/// quadratic space between 0 and 1 is not enough precision for most
 21		/// Farseer operations. The ScaleFactor helps to scale quadratic space
 22		/// up to 1000 units for Farseer and to make all methods work correctly.
 23		/// </summary>
 24		internal const float ScaleFactor = 1000.0f;
 25
 26		/// <summary>
 27		/// Inverse of ScaleFactor (1.0f / ScaleFactor)
 28		/// </summary>
 29		internal const float InvScaleFactor = 1.0f / ScaleFactor;
 30		#endregion
 31
 32		#region Internal
 33
 34		#region farseerPhysicsWorld (Internal)
 35		/// <summary>
 36		/// Farseer Physic World.
 37		/// </summary>
 38		internal World farseerPhysicsWorld;
 39		#endregion
 40
 41		#endregion
 42
 43		#region Constructors
 44		/// <summary>
 45		/// Constructor
 46		/// </summary>
 47		public FarseerPhysics()
 48			: base(true, "Farseer")
 49		{
 50			// Create a new physics world, with zero gravity.
 51			// The gravity can set later.
 52			farseerPhysicsWorld = new World(Vector2.Zero);
 53
 54			// No CCD physics.
 55			Settings.ContinuousPhysics = false;
 56		}
 57		#endregion
 58
 59		#region IsShapeSupported (Public)
 60		/// <summary>
 61		/// Gets whether the current physics module supports given shape type.
 62		/// </summary>
 63		/// <param name="shapeType">Type of the shape.</param>
 64		/// <returns>
 65		///   <c>true</c> if [is shape supported] [the specified shape type]; otherwise, <c>false</c>.
 66		/// </returns>
 67		public override bool IsShapeSupported(ShapeType shapeType)
 68		{
 69			switch (shapeType)
 70			{
 71				case ShapeType.Circle:
 72				case ShapeType.Ellipse:
 73				case ShapeType.Rectangle:
 74				case ShapeType.Polygon:
 75				case ShapeType.Compound:
 76				case ShapeType.Gear:
 77					return true;
 78			}
 79
 80			return false;
 81		}
 82		#endregion
 83
 84		#region IsJointSupported (Public)
 85		/// <summary>
 86		/// Gets whether the current physics module supports given joint type.
 87		/// </summary>
 88		/// <param name="shapeType">Type of the shape.</param>
 89		/// <returns>
 90		///   <c>true</c> if [is joint supported] [the specified shape type]; otherwise, <c>false</c>.
 91		/// </returns>
 92		public override bool IsJointSupported(JointType shapeType)
 93		{
 94			switch (shapeType)
 95			{
 96				case JointType.Angle:
 97				case JointType.Prismatic:
 98				case JointType.PointPointDistance:
 99					return true;
100			}
101
102			return false;
103		}
104		#endregion
105
106		#region IsFeatureSupported (Public)
107		/// <summary>
108		/// Gets whether the current physics module supports given feature.
109		/// </summary>
110		/// <param name="support">The support.</param>
111		/// <returns>
112		///   <c>true</c> if the specific feature is supported, <c>false</c> otherwise.
113		/// </returns>
114		public override bool IsFeatureSupported(FeatureSupport support)
115		{
116			switch (support)
117			{
118				case FeatureSupport.Joint:
119					return true;
120			}
121
122			return false;
123		}
124		#endregion
125
126		#region SetGroundPlane (Public)
127		/// <summary>
128		/// Implementation of SetGroundPlane
129		/// </summary>
130		/// <param name="enable">True to enable, false otherwise.</param>
131		/// <param name="height">The height of the plane.</param>
132		public override void SetGroundPlane(bool enable, float height)
133		{
134		}
135		#endregion
136
137		#region Methods (Private)
138
139		#region CreateBody
140		protected override PhysicsBody CreateBody(bool is2D,
141			PhysicsShape shape, Vector initialPosition)
142		{
143			if (is2D == false)
144			{
145				Log.Warning("Farseer does not support 3D bodies.");
146				return null;
147			}
148
149			FarseerBody body = new FarseerBody(this, shape, initialPosition);
150			bodies.Add(body);
151			return body;
152		}
153		#endregion
154
155		#region CreateJoint
156		public override PhysicsJoint CreateJoint(
157			JointType jointType,
158			PhysicsBody bodyA,
159			PhysicsBody bodyB,
160			object[] args)
161		{
162			if (IsJointSupported(jointType) == false)
163			{
164				Log.Warning("Current module does not support " +
165				            "the type of joint " + jointType);
166				return null;
167			}
168
169			PhysicsJoint joint = new FarseerJoint(this, jointType, bodyA, bodyB, args);
170			if (joint != null)
171			{
172				joints.Add(joint);
173			}
174			return joint;
175		}
176		#endregion
177
178		#region RemoveBodyImpl
179		protected override void RemoveBodyImpl(PhysicsBody body)
180		{
181			// Remove body from farseer world
182			farseerPhysicsWorld.RemoveBody(
183				(body as FarseerBody).Body
184				);
185		}
186		#endregion
187
188		#region RemoveJointImpl
189		protected override void RemoveJointImpl(PhysicsJoint joint)
190		{
191			// Remove body from farseer world
192			farseerPhysicsWorld.RemoveJoint(
193				(joint as FarseerJoint).Joint
194				);
195		}
196		#endregion
197
198		#region RayCastImpl
199		/// <summary>
200		/// Rays the cast impl.
201		/// </summary>
202		/// <param name="ray">The ray.</param>
203		/// <param name="foundBody">The found body.</param>
204		/// <param name="surfaceNormal">The surface normal.</param>
205		/// <param name="fraction">The fraction.</param>
206		/// <param name="userData">The user data.</param>
207		/// <param name="checkGround">Whether to perform ray cast on 2D ground too.</param>
208		/// <returns>True if any intersection happen, false otherwise.</returns>
209		protected override bool RayCastImpl(Ray ray, bool checkGround,
210			out PhysicsBody foundBody, out Vector surfaceNormal, out float fraction,
211			out object userData)
212		{
213			foundBody = null;
214			fraction = 0.0f;
215			surfaceNormal = Vector.Zero;
216			userData = null;
217			Log.Warning(
218				@"Farseer physics does not perform 3D ray cast...Please use 
219				FindRayCast2D");
220			return false;
221		}
222		#endregion
223
224		#region RayCastImpl2D
225		/// <summary>
226		/// Rays the cast impl 2D.
227		/// </summary>
228		/// <param name="point1">The point1.</param>
229		/// <param name="point2">The point2.</param>
230		/// <param name="outBody">The out body.</param>
231		/// <param name="normal">The normal.</param>
232		/// <param name="fraction">The fraction.</param>
233		/// <returns>True if any intersection was found.</returns>
234		protected override bool RayCastImpl2D(Point point1, Point point2,
235			out PhysicsBody outBody, out Point normal, out float fraction)
236		{
237			PhysicsBody foundBody = null;
238			Point foundNormal = Point.Zero;
239			float foundFraction = 0.0f;
240			bool result = false;
241			farseerPhysicsWorld.RayCast((fixture, p, n, fr) =>
242			{
243				foundBody = FindBodyByFixture(fixture);
244				FarseerDatatypesMapping.Convert(ref n, out foundNormal);
245				foundNormal *= InvScaleFactor;
246				foundFraction = fr;
247				result = true;
248				return 1;
249			},
250				FarseerDatatypesMapping.Convert(ref point1) * ScaleFactor,
251				FarseerDatatypesMapping.Convert(ref point2) * ScaleFactor);
252
253			outBody = foundBody;
254			normal = foundNormal;
255			fraction = foundFraction;
256			return result;
257		}
258		#endregion
259
260		#region SetGravity
261		protected override void SetGravity(Vector gravity)
262		{
263			var valueToSet = FarseerDatatypesMapping.Convert(ref gravity) *
264			                 ScaleFactor;
265			farseerPhysicsWorld.Gravity = valueToSet;
266		}
267		#endregion
268
269		#region GetTotalPhysicsTime
270		protected override double GetTotalPhysicsTime()
271		{
272			return farseerPhysicsWorld.UpdateTime;
273		}
274		#endregion
275
276		#region SetMultithreading
277		protected override void SetMultithreading(bool enable)
278		{
279			// Not supported
280			if (enable)
281			{
282				Log.Warning("Farseer does not support multi-threading yet!");
283			}
284		}
285		#endregion
286
287		#region UpdateSimulation
288		/// <summary>
289		/// Perform Farseer simulation step.
290		/// </summary>
291		protected override void UpdateSimulation(float timeStep)
292		{
293			// Update profiling update time also
294			profilingInfo.UpdateTime = farseerPhysicsWorld.UpdateTime;
295
296			if (IsPaused == false)
297			{
298				farseerPhysicsWorld.Step(timeStep);
299				//if (Delta.Engine.Time.CheckEvery(1.0f / 30.0f))
300				//{
301				//  farseerPhysicsWorld.Step(1.0f / 30.0f);
302				//}
303			}
304		}
305		#endregion
306
307		#region FindBodyByFixture
308		/// <summary>
309		/// Find a farseer object by body.
310		/// </summary>
311		/// <param name="fixtureToFind">Farseer fixture to search for.</param>
312		/// <returns>Farseer physics body or null if not found.</returns>
313		internal FarseerBody FindBodyByFixture(Fixture fixtureToFind)
314		{
315			// Iterate through all farseer objects.
316			for (int index = 0; index < bodies.Count; index++)
317			{
318				FarseerBody farseerBody = bodies[index] as FarseerBody;
319
320				// Now iterate fixture of Farseer body
321				if (farseerBody == null)
322				{
323					continue;
324				}
325
326				// Iterate again for Farseer fixture
327				foreach (Fixture iter in farseerBody.Body.FixtureList)
328				{
329					// If we find the right fixture, return the object.
330					if (iter == fixtureToFind)
331					{
332						return farseerBody;
333					}
334				}
335			}
336			return null;
337		}
338		#endregion
339
340		#endregion
341
342		/// <summary>
343		/// Tests
344		/// </summary>
345		internal class FarseerPhysicsTests
346		{
347			#region TestInitialization (Static)
348			/// <summary>
349			/// Test whether initialization has been done.
350			/// </summary>
351			[Test]
352			public static void TestInitialization()
353			{
354				// check that everything has been OK with Physics initiallization
355				Assert.NotNull(Bodies);
356			}
357			#endregion
358
359			#region TestCreate2DBodyWithShape (Static)
360			/// <summary>
361			/// Test creation of 2D body with shape.
362			/// </summary>
363			[Test]
364			public static void TestCreate2DBodyWithShape()
365			{
366				PhysicsBody body = CreateCircle(2.0f, 1.0f);
367				Assert.NotNull(body);
368				Assert.NotNull(body.Shape);
369			}
370			#endregion
371
372			#region TestFeatureSupport (Static)
373			/// <summary>
374			/// Test whether given feature is supoorted.
375			/// </summary>
376			[Test]
377			public static void TestFeatureSupport()
378			{
379				// Farseer should support joint.
380				bool isSupported = Instance.IsFeatureSupported(
381					FeatureSupport.Joint);
382
383				Assert.True(isSupported);
384			}
385			#endregion
386
387			#region TestShapeSupport (Static)
388			/// <summary>
389			/// Test whether given shape is supoorted.
390			/// </summary>
391			[Test]
392			public static void TestShapeSupport()
393			{
394				// farseer support circle shape. 
395				bool isSupported = Instance.IsShapeSupported(
396					ShapeType.Circle);
397
398				Assert.True(isSupported);
399			}
400			#endregion
401		}
402	}
403}