PageRenderTime 155ms CodeModel.GetById 121ms app.highlight 14ms RepoModel.GetById 16ms app.codeStats 0ms

/PhysicsEngines/JigLib/JigLibController.cs

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