PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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