PageRenderTime 24ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/PhysicsEngines/JigLib/JigLibController.cs

#
C# | 476 lines | 279 code | 58 blank | 139 comment | 9 complexity | e1ae7160653231ee07340271352e9395 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using Delta.Engine.Game.Interfaces;
  4. using Delta.Utilities.Datatypes;
  5. using Delta.Utilities.Helpers;
  6. using JigLibX.Collision;
  7. using JigLibX.Physics;
  8. namespace Delta.PhysicsEngines.JigLib
  9. {
  10. /// <summary>
  11. /// Class that is used to control a physical object with JigLib.
  12. /// </summary>
  13. internal class JigLibController
  14. : Controller,
  15. IController
  16. {
  17. #region Attachable (Public)
  18. /// <summary>
  19. /// Gets or Sets the attachable that is controlled.
  20. /// </summary>
  21. public IAttachable Attachable
  22. {
  23. get;
  24. set;
  25. }
  26. #endregion
  27. #region MovingDirection (Public)
  28. /// <summary>
  29. /// Gets or Sets the moving direction of the PhysicsBody.
  30. /// </summary>
  31. public Vector MovingDirection
  32. {
  33. get;
  34. set;
  35. }
  36. #endregion
  37. #region MoveSpeed (Public)
  38. /// <summary>
  39. /// Gets or Sets the speed at which the PhysicsBody moves.
  40. /// </summary>
  41. public float MoveSpeed
  42. {
  43. get;
  44. set;
  45. }
  46. #endregion
  47. #region JumpStrength (Public)
  48. /// <summary>
  49. /// Gets or Sets the measure of the strength that the PhysicsBody jumps.
  50. /// </summary>
  51. public float JumpStrength
  52. {
  53. get;
  54. set;
  55. }
  56. #endregion
  57. #region MaxUpSpeed (Public)
  58. /// <summary>
  59. /// Maximum up speed
  60. /// </summary>
  61. public float MaxUpSpeed
  62. {
  63. get;
  64. set;
  65. }
  66. #endregion
  67. #region AllowedGroundDistance (Public)
  68. /// <summary>
  69. /// Allowed distance to ground
  70. /// </summary>
  71. public float AllowedGroundDistance
  72. {
  73. get;
  74. set;
  75. }
  76. #endregion
  77. #region ForwardDirection (Public)
  78. /// <summary>
  79. /// Forward direction
  80. /// </summary>
  81. public Vector ForwardDirection
  82. {
  83. get;
  84. private set;
  85. }
  86. #endregion
  87. #region RightDirection (Public)
  88. /// <summary>
  89. /// Right direction
  90. /// </summary>
  91. public Vector RightDirection
  92. {
  93. get;
  94. private set;
  95. }
  96. #endregion
  97. #region BackwardDirection (Public)
  98. /// <summary>
  99. /// Backward direction, stored for faster accesss
  100. /// </summary>
  101. public Vector BackwardDirection
  102. {
  103. get;
  104. private set;
  105. }
  106. #endregion
  107. #region LeftDirection (Public)
  108. /// <summary>
  109. /// Left direction, stored for faster accesss
  110. /// </summary>
  111. public Vector LeftDirection
  112. {
  113. get;
  114. private set;
  115. }
  116. #endregion
  117. #region UpDirection (Public)
  118. /// <summary>
  119. /// Right direction, stored for faster accesss
  120. /// </summary>
  121. public Vector UpDirection
  122. {
  123. get;
  124. private set;
  125. }
  126. #endregion
  127. #region Private
  128. #region physicsManager (Private)
  129. private JigLibPhysics physicsManager;
  130. #endregion
  131. #region extImpulse (Private)
  132. /// <summary>
  133. /// External impulse applied to the ControlledObject (usually from jump).
  134. /// </summary>
  135. private Vector extImpulse = Vector.Zero;
  136. #endregion
  137. #region controlledBody (Private)
  138. /// <summary>
  139. /// The object that is controlled by the class
  140. /// </summary>
  141. private readonly JigLibBody controlledBody;
  142. #endregion
  143. #endregion
  144. #region Constructors
  145. /// <summary>
  146. /// Create a Controller using Jiglib
  147. /// </summary>
  148. /// <param name="physicsManager">The physics manager.</param>
  149. /// <param name="setControlledObject">The set controlled object.</param>
  150. public JigLibController(
  151. JigLibPhysics physicsManager,
  152. JigLibBody setControlledObject)
  153. :
  154. this(physicsManager, setControlledObject, 1, 1, 1,
  155. Vector.UnitX + Vector.UnitY, Vector.UnitX - Vector.UnitY)
  156. {
  157. }
  158. /// <summary>
  159. /// Create a Controller using Jiglib
  160. /// </summary>
  161. /// <param name="physicsManager">The physics manager.</param>
  162. /// <param name="setControlledObject">The set controlled object.</param>
  163. /// <param name="setMoveSpeed">Moving speed</param>
  164. /// <param name="setJumpStrength">Jump strength</param>
  165. /// <param name="allowedGroundDistance">The allowed ground distance.</param>
  166. public JigLibController(JigLibPhysics physicsManager,
  167. JigLibBody setControlledObject,
  168. float setMoveSpeed, float setJumpStrength, float allowedGroundDistance)
  169. :
  170. this(physicsManager, setControlledObject, setMoveSpeed,
  171. setJumpStrength, allowedGroundDistance, Vector.UnitX + Vector.UnitY,
  172. Vector.UnitX - Vector.UnitY)
  173. {
  174. }
  175. // JiglibController()
  176. /// <summary>
  177. /// Create a Controller using Jiglib
  178. /// </summary>
  179. /// <param name="physicsManager">The physics manager.</param>
  180. /// <param name="setControlledObject">The set controlled object.</param>
  181. /// <param name="setMoveSpeed">The set move speed.</param>
  182. /// <param name="setJumpStrength">The set jump strength.</param>
  183. /// <param name="allowedGroundDistance">The allowed ground distance.</param>
  184. /// <param name="setForwardDirection">The set forward direction.</param>
  185. /// <param name="setRightDirection">The set right direction.</param>
  186. public JigLibController(JigLibPhysics physicsManager,
  187. JigLibBody setControlledObject,
  188. float setMoveSpeed, float setJumpStrength, float allowedGroundDistance,
  189. Vector setForwardDirection, Vector setRightDirection)
  190. : this(physicsManager, setControlledObject, setMoveSpeed,
  191. setJumpStrength, 1.0f, allowedGroundDistance, setForwardDirection,
  192. setRightDirection)
  193. {
  194. }
  195. // JiglibController()
  196. /// <summary>
  197. /// Create a Controller using Jiglib
  198. /// </summary>
  199. /// <param name="physicsManager">The physics manager.</param>
  200. /// <param name="setControlledObject">The set controlled object.</param>
  201. /// <param name="setMoveSpeed">The set move speed.</param>
  202. /// <param name="setJumpStrength">The set jump strength.</param>
  203. /// <param name="setMaxUpSpeed">The set max up speed.</param>
  204. /// <param name="allowedGroundDistance">The allowed ground distance.</param>
  205. /// <param name="setForwardDirection">The set forward direction.</param>
  206. /// <param name="setRightDirection">The set right direction.</param>
  207. public JigLibController(JigLibPhysics physicsManager,
  208. JigLibBody setControlledObject,
  209. float setMoveSpeed, float setJumpStrength, float setMaxUpSpeed,
  210. float allowedGroundDistance, Vector setForwardDirection,
  211. Vector setRightDirection)
  212. {
  213. //Input.InputInstance.CommandEvent += new InputEventDelegate(OnInputEvent);
  214. this.physicsManager = physicsManager;
  215. MoveSpeed = setMoveSpeed;
  216. JumpStrength = setJumpStrength;
  217. MaxUpSpeed = setMaxUpSpeed;
  218. AllowedGroundDistance = allowedGroundDistance;
  219. ForwardDirection = setForwardDirection;
  220. ForwardDirection.Normalize();
  221. BackwardDirection = Vector.Zero - ForwardDirection;
  222. BackwardDirection.Normalize();
  223. RightDirection = setRightDirection;
  224. RightDirection.Normalize();
  225. LeftDirection = Vector.Zero - RightDirection;
  226. LeftDirection.Normalize();
  227. CalculateUpDirection();
  228. MovingDirection = Vector.Zero;
  229. controlledBody = setControlledObject;
  230. EnableController();
  231. }
  232. #endregion
  233. #region UpdateController (Public)
  234. /// <summary>
  235. /// UpdateController is inherited from JigLib Controller and
  236. /// allows direct manipulation of the physic state of an object. Here
  237. /// is used to update the position of the ControlledObject according to
  238. /// user input.
  239. /// </summary>
  240. /// <param name="dt">Delta time to update controller.</param>
  241. public override void UpdateController(float dt)
  242. {
  243. // controlled objects should always be active!!!
  244. controlledBody.Body.SetActive();
  245. ApplyMovementDirect();
  246. controlledBody.Body.ApplyWorldImpulse(
  247. JigLibDatatypesMapping.Convert(ref extImpulse));
  248. // reset internal variables
  249. ResetInternalMovementData();
  250. }
  251. #endregion
  252. #region Methods (Private)
  253. #region ResetInternalMovementData
  254. /// <summary>
  255. /// Reset internal movement data
  256. /// </summary>
  257. private void ResetInternalMovementData()
  258. {
  259. MovingDirection = extImpulse = Vector.Zero;
  260. }
  261. #endregion
  262. // ResetInternalMovementData()
  263. #region ApplyMovementDirect
  264. /// <summary>
  265. /// Apply the movement components directly in the objects velocity
  266. /// </summary>
  267. private void ApplyMovementDirect()
  268. {
  269. // get the vertical component of the velocity
  270. float verticalVelocity = Vector.Dot(UpDirection,
  271. controlledBody.LinearVelocity);
  272. MaxUpSpeed = 1.0f;
  273. // limit the up velocity to avoid huge jumps
  274. float upSpeed = verticalVelocity >= MaxUpSpeed
  275. ? MaxUpSpeed
  276. : verticalVelocity;
  277. // calculate final upVelocity
  278. Vector upVelocity = upSpeed * UpDirection;
  279. // see if we got a moving direction
  280. if (MovingDirection.Length <= 0.00001f)
  281. {
  282. //if (CheckOnAirCollisionNormal())
  283. if (CheckOnAirRayCast())
  284. {
  285. // keep the vertical component of the speed
  286. //controlledObject.Velocity = controlledObject.Velocity;
  287. }
  288. else
  289. {
  290. // stop the object
  291. controlledBody.LinearVelocity = Vector.Zero;
  292. }
  293. } // if
  294. else
  295. {
  296. MovingDirection.Normalize();
  297. //float damp = 1.0f;// 10.0f * dt;
  298. //if (CheckOnAirCollisionNormal())
  299. if (CheckOnAirRayCast())
  300. {
  301. if (HasCollisions())
  302. {
  303. //controlledObject.Velocity -= verticalVelocity * UpDirection;
  304. //controlledObject.Velocity += upVelocity;
  305. //controlledObject.Velocity += 0.01f * MoveSpeed * movingDirection;
  306. //controlledObject.Velocity -= damp * verticalVelocity * UpDirection;
  307. }
  308. else
  309. {
  310. controlledBody.LinearVelocity = upVelocity;
  311. controlledBody.LinearVelocity += MoveSpeed * MovingDirection;
  312. }
  313. } // if
  314. else
  315. {
  316. //movingDirection = Vector.Normalize(movingDirection);
  317. controlledBody.LinearVelocity = MoveSpeed * MovingDirection;
  318. //controlledObject.Velocity = upVelocity;
  319. //controlledObject.Velocity += MoveSpeed * movingDirection;
  320. }
  321. }
  322. }
  323. #endregion
  324. #region HasCollisions
  325. /// <summary>
  326. /// Has collisions
  327. /// </summary>
  328. /// <returns>True if has collisions, false otherwise.</returns>
  329. private bool HasCollisions()
  330. {
  331. return controlledBody.Skin.Collisions.Count > 0;
  332. }
  333. #endregion
  334. #region CheckOnAirCollisionNormal
  335. /// <summary>
  336. /// Check if the ControlledObject is on air, i.e. does not collide with
  337. /// anything on the ground, by inspecting the normal of colliding geometries
  338. /// </summary>
  339. /// <returns>True if on air false otherwise.</returns>
  340. private bool CheckOnAirCollisionNormal()
  341. {
  342. List<CollisionInfo> collisionInfo =
  343. controlledBody.Skin.Collisions;
  344. bool isOnAir = true;
  345. if (collisionInfo.Count > 0)
  346. {
  347. for (int i = 0; i < collisionInfo.Count; i++)
  348. {
  349. CollisionInfo info = collisionInfo[i];
  350. Vector dirToBody;
  351. JigLibDatatypesMapping.Convert(info.DirToBody0, out dirToBody);
  352. dirToBody.Normalize();
  353. //Vector groundSupport = dirToBody;//+= DirToBody;
  354. // if the collision normal has an angle bigger than 30 degrees
  355. // then we consider that the body can "support" on this
  356. if (Vector.Dot(dirToBody, UpDirection) > 0.866f)
  357. {
  358. // adjust the moving direction according to the slope of the ground
  359. Vector helpVec = Vector.Cross(MovingDirection, UpDirection);
  360. MovingDirection = Vector.Cross(dirToBody, helpVec);
  361. return false;
  362. }
  363. }
  364. }
  365. return isOnAir;
  366. }
  367. #endregion
  368. #region CheckOnAirRayCast
  369. /// <summary>
  370. /// Check if object is on the air, i.e. does not collide with
  371. /// anything on the ground, using ray casting.
  372. /// </summary>
  373. /// <returns>True if any intersection happen, false otherwise.</returns>
  374. private bool CheckOnAirRayCast()
  375. {
  376. //float distToFloorSquare = AllowedGroundDistance * AllowedGroundDistance;
  377. Vector position = controlledBody.Position;
  378. Vector normal; // = new Vector();
  379. float fractions;
  380. Object userData;
  381. Ray downRay = new Ray(position, Vector.Zero - UpDirection);
  382. PhysicsBody castObjects;
  383. if (Physics.FindRayCast(
  384. downRay, true, out castObjects, out normal, out fractions, out userData))
  385. {
  386. Vector[] rayContacts = userData as Vector[];
  387. // Threat only first element.
  388. Vector rayContact = rayContacts[0];
  389. // project the distance to the surface normal so that we can walk
  390. // on inclined ground
  391. normal = Vector.Normalize(normal);
  392. Vector vertical = position - rayContact;
  393. float projection = MathHelper.Abs(Vector.Dot(vertical, normal));
  394. float penetration = AllowedGroundDistance - projection;
  395. if (penetration > 0.0f)
  396. {
  397. // quick hack for not allowing the controlled object to actually
  398. // pass through the ground
  399. controlledBody.Position += penetration * UpDirection; // normal;
  400. return false;
  401. }
  402. }
  403. return true;
  404. }
  405. #endregion
  406. #region CalculateUpDirection
  407. /// <summary>
  408. /// Calculate new up direction
  409. /// </summary>
  410. private void CalculateUpDirection()
  411. {
  412. UpDirection = Vector.Cross(RightDirection, ForwardDirection);
  413. UpDirection = Vector.Normalize(UpDirection);
  414. }
  415. #endregion
  416. #endregion
  417. }
  418. }