/SimpleFarseerPlatformer/Farseer Physics Engine 3.2 XNA/Controllers/AbstractForceController.cs

# · C# · 323 lines · 185 code · 33 blank · 105 comment · 15 complexity · 522b3e97e4593c96907ea91eecb47e75 MD5 · raw file

  1. using System;
  2. using FarseerPhysics.Dynamics;
  3. using Microsoft.Xna.Framework;
  4. namespace FarseerPhysics.Controllers
  5. {
  6. public abstract class AbstractForceController : Controller
  7. {
  8. #region DecayModes enum
  9. /// <summary>
  10. /// Modes for Decay. Actual Decay must be implemented in inheriting
  11. /// classes
  12. /// </summary>
  13. public enum DecayModes
  14. {
  15. None,
  16. Step,
  17. Linear,
  18. InverseSquare,
  19. Curve
  20. }
  21. #endregion
  22. #region ForceTypes enum
  23. /// <summary>
  24. /// Forcetypes are used in the decay math to properly get the distance.
  25. /// They are also used to draw a representation in DebugView
  26. /// </summary>
  27. public enum ForceTypes
  28. {
  29. Point,
  30. Line,
  31. Area
  32. }
  33. #endregion
  34. #region TimingModes enum
  35. /// <summary>
  36. /// Timing Modes
  37. /// Switched: Standard on/off mode using the baseclass enabled property
  38. /// Triggered: When the Trigger() method is called the force is active
  39. /// for a specified Impulse Length
  40. /// Curve: Still to be defined. The basic idea is having a Trigger
  41. /// combined with a curve for the strength
  42. /// </summary>
  43. public enum TimingModes
  44. {
  45. Switched,
  46. Triggered,
  47. Curve
  48. }
  49. #endregion
  50. /// <summary>
  51. /// Curve to be used for Decay in Curve mode
  52. /// </summary>
  53. public Curve DecayCurve;
  54. /// <summary>
  55. /// The Forcetype of the instance
  56. /// </summary>
  57. public ForceTypes ForceType;
  58. /// <summary>
  59. /// Provided for reuse to provide Variation functionality in
  60. /// inheriting classes
  61. /// </summary>
  62. protected Random Randomize;
  63. /// <summary>
  64. /// Curve used by Curve Mode as an animated multiplier for the force
  65. /// strength.
  66. /// Only positions between 0 and 1 are considered as that range is
  67. /// stretched to have ImpulseLength.
  68. /// </summary>
  69. public Curve StrengthCurve;
  70. /// <summary>
  71. /// Constructor
  72. /// </summary>
  73. public AbstractForceController()
  74. : base(ControllerType.AbstractForceController)
  75. {
  76. Enabled = true;
  77. Strength = 1.0f;
  78. Position = new Vector2(0, 0);
  79. MaximumSpeed = 100.0f;
  80. TimingMode = TimingModes.Switched;
  81. ImpulseTime = 0.0f;
  82. ImpulseLength = 1.0f;
  83. Triggered = false;
  84. StrengthCurve = new Curve();
  85. Variation = 0.0f;
  86. Randomize = new Random(1234);
  87. DecayMode = DecayModes.None;
  88. DecayCurve = new Curve();
  89. DecayStart = 0.0f;
  90. DecayEnd = 0.0f;
  91. StrengthCurve.Keys.Add(new CurveKey(0, 5));
  92. StrengthCurve.Keys.Add(new CurveKey(0.1f, 5));
  93. StrengthCurve.Keys.Add(new CurveKey(0.2f, -4));
  94. StrengthCurve.Keys.Add(new CurveKey(1f, 0));
  95. }
  96. /// <summary>
  97. /// Overloaded Contstructor with supplying Timing Mode
  98. /// </summary>
  99. /// <param name="mode"></param>
  100. public AbstractForceController(TimingModes mode)
  101. : base(ControllerType.AbstractForceController)
  102. {
  103. TimingMode = mode;
  104. switch (mode)
  105. {
  106. case TimingModes.Switched:
  107. Enabled = true;
  108. break;
  109. case TimingModes.Triggered:
  110. Enabled = false;
  111. break;
  112. case TimingModes.Curve:
  113. Enabled = false;
  114. break;
  115. }
  116. }
  117. /// <summary>
  118. /// Global Strength of the force to be applied
  119. /// </summary>
  120. public float Strength { get; set; }
  121. /// <summary>
  122. /// Position of the Force. Can be ignored (left at (0,0) for forces
  123. /// that are not position-dependent
  124. /// </summary>
  125. public Vector2 Position { get; set; }
  126. /// <summary>
  127. /// Maximum speed of the bodies. Bodies that are travelling faster are
  128. /// supposed to be ignored
  129. /// </summary>
  130. public float MaximumSpeed { get; set; }
  131. /// <summary>
  132. /// Maximum Force to be applied. As opposed to Maximum Speed this is
  133. /// independent of the velocity of
  134. /// the affected body
  135. /// </summary>
  136. public float MaximumForce { get; set; }
  137. /// <summary>
  138. /// Timing Mode of the force instance
  139. /// </summary>
  140. public TimingModes TimingMode { get; set; }
  141. /// <summary>
  142. /// Time of the current impulse. Incremented in update till
  143. /// ImpulseLength is reached
  144. /// </summary>
  145. public float ImpulseTime { get; private set; }
  146. /// <summary>
  147. /// Length of a triggered impulse. Used in both Triggered and Curve Mode
  148. /// </summary>
  149. public float ImpulseLength { get; set; }
  150. /// <summary>
  151. /// Indicating if we are currently during an Impulse
  152. /// (Triggered and Curve Mode)
  153. /// </summary>
  154. public bool Triggered { get; private set; }
  155. /// <summary>
  156. /// Variation of the force applied to each body affected
  157. /// !! Must be used in inheriting classes properly !!
  158. /// </summary>
  159. public float Variation { get; set; }
  160. /// <summary>
  161. /// See DecayModes
  162. /// </summary>
  163. public DecayModes DecayMode { get; set; }
  164. /// <summary>
  165. /// Start of the distance based Decay. To set a non decaying area
  166. /// </summary>
  167. public float DecayStart { get; set; }
  168. /// <summary>
  169. /// Maximum distance a force should be applied
  170. /// </summary>
  171. public float DecayEnd { get; set; }
  172. /// <summary>
  173. /// Calculate the Decay for a given body. Meant to ease force
  174. /// development and stick to the DRY principle and provide unified and
  175. /// predictable decay math.
  176. /// </summary>
  177. /// <param name="body">The body to calculate decay for</param>
  178. /// <returns>A multiplier to multiply the force with to add decay
  179. /// support in inheriting classes</returns>
  180. protected float GetDecayMultiplier(Body body)
  181. {
  182. //TODO: Consider ForceType in distance calculation!
  183. float distance = (body.Position - Position).Length();
  184. switch (DecayMode)
  185. {
  186. case DecayModes.None:
  187. {
  188. return 1.0f;
  189. }
  190. case DecayModes.Step:
  191. {
  192. if (distance < DecayEnd)
  193. return 1.0f;
  194. else
  195. return 0.0f;
  196. }
  197. case DecayModes.Linear:
  198. {
  199. if (distance < DecayStart)
  200. return 1.0f;
  201. if (distance > DecayEnd)
  202. return 0.0f;
  203. return (DecayEnd - DecayStart/distance - DecayStart);
  204. }
  205. case DecayModes.InverseSquare:
  206. {
  207. if (distance < DecayStart)
  208. return 1.0f;
  209. else
  210. return 1.0f/((distance - DecayStart)*(distance - DecayStart));
  211. }
  212. case DecayModes.Curve:
  213. {
  214. if (distance < DecayStart)
  215. return 1.0f;
  216. else
  217. return DecayCurve.Evaluate(distance - DecayStart);
  218. }
  219. default:
  220. return 1.0f;
  221. }
  222. }
  223. /// <summary>
  224. /// Triggers the trigger modes (Trigger and Curve)
  225. /// </summary>
  226. public void Trigger()
  227. {
  228. Triggered = true;
  229. ImpulseTime = 0;
  230. }
  231. /// <summary>
  232. /// Inherited from Controller
  233. /// Depending on the TimingMode perform timing logic and call ApplyForce()
  234. /// </summary>
  235. /// <param name="dt"></param>
  236. public override void Update(float dt)
  237. {
  238. switch (TimingMode)
  239. {
  240. case TimingModes.Switched:
  241. {
  242. if (Enabled)
  243. {
  244. ApplyForce(dt, Strength);
  245. }
  246. break;
  247. }
  248. case TimingModes.Triggered:
  249. {
  250. if (Enabled && Triggered)
  251. {
  252. if (ImpulseTime < ImpulseLength)
  253. {
  254. ApplyForce(dt, Strength);
  255. ImpulseTime += dt;
  256. }
  257. else
  258. {
  259. Triggered = false;
  260. }
  261. }
  262. break;
  263. }
  264. case TimingModes.Curve:
  265. {
  266. if (Enabled && Triggered)
  267. {
  268. if (ImpulseTime < ImpulseLength)
  269. {
  270. ApplyForce(dt, Strength*StrengthCurve.Evaluate(ImpulseTime));
  271. ImpulseTime += dt;
  272. }
  273. else
  274. {
  275. Triggered = false;
  276. }
  277. }
  278. break;
  279. }
  280. }
  281. }
  282. /// <summary>
  283. /// Apply the force supplying strength (wich is modified in Update()
  284. /// according to the TimingMode
  285. /// </summary>
  286. /// <param name="dt"></param>
  287. /// <param name="strength">The strength</param>
  288. public abstract void ApplyForce(float dt, float strength);
  289. }
  290. }