Joint.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using System;
  4. using System.Runtime.InteropServices;
  5. namespace BansheeEngine
  6. {
  7. /// <summary>
  8. /// Base class for all Joint types. Joints constrain how two rigidbodies move relative to one another (e.g. a door
  9. /// hinge). One of the bodies in the joint must always be movable (i.e. non-kinematic).
  10. /// </summary>
  11. public abstract class Joint : Component
  12. {
  13. internal NativeJoint native;
  14. [SerializeField]
  15. internal SerializableData serializableData = new SerializableData();
  16. /// <summary>
  17. /// Triggered when the joint's break force or torque is exceeded.
  18. /// </summary>
  19. public event Action OnJointBreak;
  20. /// <summary>
  21. /// Maximum force the joint can apply before breaking. Broken joints no longer participate in physics simulation.
  22. /// </summary>
  23. public float BreakForce
  24. {
  25. get { return serializableData.breakForce; }
  26. set
  27. {
  28. if (serializableData.breakForce == value)
  29. return;
  30. serializableData.breakForce = value;
  31. if (native != null)
  32. native.BreakForce = value;
  33. }
  34. }
  35. /// <summary>
  36. /// Sets the maximum force the joint can apply before breaking. Broken joints no longer participate in physics
  37. /// simulation.
  38. /// </summary>
  39. public float BreakTorque
  40. {
  41. get { return serializableData.breakTorque; }
  42. set
  43. {
  44. if (serializableData.breakTorque == value)
  45. return;
  46. serializableData.breakTorque = value;
  47. if (native != null)
  48. native.BreakTorque = value;
  49. }
  50. }
  51. /// <summary>
  52. /// Determines whether collisions between the two bodies managed by the joint are enabled.
  53. /// </summary>
  54. public bool EnableCollision
  55. {
  56. get { return serializableData.enableCollision; }
  57. set
  58. {
  59. if (serializableData.enableCollision == value)
  60. return;
  61. serializableData.enableCollision = value;
  62. if (native != null)
  63. native.EnableCollision = value;
  64. }
  65. }
  66. /// <summary>
  67. /// Returns one of the bodies managed by the joint.
  68. /// </summary>
  69. /// <param name="body">Which of the rigidbodies to return.</param>
  70. /// <returns>Rigidbody managed by the joint, or null if none.</returns>
  71. public Rigidbody GetRigidbody(JointBody body)
  72. {
  73. return serializableData.bodies[(int) body];
  74. }
  75. /// <summary>
  76. /// Sets a body managed by the joint. One of the bodies must be movable (i.e. non-kinematic).
  77. /// </summary>
  78. /// <param name="body">Which of the rigidbodies to set.</param>
  79. /// <param name="rigidbody">Rigidbody to managed by the joint, or null. If one of the bodies is null the other
  80. /// one will be anchored globally to the position/rotation set by <see cref="SetPosition"/>
  81. /// and <see cref="SetRotation"/>.</param>
  82. public void SetRigidbody(JointBody body, Rigidbody rigidbody)
  83. {
  84. if (serializableData.bodies[(int)body] == rigidbody)
  85. return;
  86. if (serializableData.bodies[(int)body] != null)
  87. serializableData.bodies[(int)body].SetJoint(null);
  88. serializableData.bodies[(int)body] = rigidbody;
  89. if (rigidbody != null)
  90. serializableData.bodies[(int)body].SetJoint(this);
  91. if (native != null)
  92. {
  93. native.SetRigidbody(body, rigidbody);
  94. UpdateTransform(body);
  95. }
  96. }
  97. /// <summary>
  98. /// Returns the position at which the body is anchored to the joint.
  99. /// </summary>
  100. /// <param name="body">Which body to retrieve position for.</param>
  101. /// <returns>Position relative to the body.</returns>
  102. public Vector3 GetPosition(JointBody body)
  103. {
  104. return serializableData.positions[(int)body];
  105. }
  106. /// <summary>
  107. /// Sets the position at which the body is anchored to the joint.
  108. /// </summary>
  109. /// <param name="body">Which body set the position for.</param>
  110. /// <param name="position">Position relative to the body.</param>
  111. public void SetPosition(JointBody body, Vector3 position)
  112. {
  113. if (serializableData.positions[(int)body] == position)
  114. return;
  115. serializableData.positions[(int) body] = position;
  116. if (native != null)
  117. UpdateTransform(body);
  118. }
  119. /// <summary>
  120. /// Returns the rotation at which the body is anchored to the joint.
  121. /// </summary>
  122. /// <param name="body">Which body to retrieve rotation for.</param>
  123. /// <returns>Rotation relative to the body.</returns>
  124. public Quaternion GetRotation(JointBody body)
  125. {
  126. return serializableData.rotations[(int)body];
  127. }
  128. /// <summary>
  129. /// Sets the rotation at which the body is anchored to the joint.
  130. /// </summary>
  131. /// <param name="body">Which body set the rotation for.</param>
  132. /// <param name="rotation">Rotation relative to the body.</param>
  133. public void SetRotation(JointBody body, Quaternion rotation)
  134. {
  135. if (serializableData.rotations[(int)body] == rotation)
  136. return;
  137. serializableData.rotations[(int)body] = rotation;
  138. if (native != null)
  139. UpdateTransform(body);
  140. }
  141. /// <summary>
  142. /// Triggered when the joint breaks.
  143. /// </summary>
  144. internal void DoOnJointBreak()
  145. {
  146. if (OnJointBreak != null)
  147. OnJointBreak();
  148. }
  149. /// <summary>
  150. /// Notifies the joint that one of the attached rigidbodies moved and that its transform needs updating.
  151. /// </summary>
  152. /// <param name="body">Rigidbody that moved.</param>
  153. internal void NotifyRigidbodyMoved(Rigidbody body)
  154. {
  155. // If physics update is in progress do nothing, as its the joint itself that's probably moving the body
  156. if (Physics.IsUpdateInProgress)
  157. return;
  158. if (serializableData.bodies[0] == body)
  159. UpdateTransform(JointBody.A);
  160. else if (serializableData.bodies[1] == body)
  161. UpdateTransform(JointBody.B);
  162. }
  163. /// <summary>
  164. /// Creates the internal representation of the Joint for use by the component.
  165. /// </summary>
  166. /// <returns>New native joint object.</returns>
  167. internal abstract NativeJoint CreateNative();
  168. private void OnInitialize()
  169. {
  170. NotifyFlags = TransformChangedFlags.Transform | TransformChangedFlags.Parent;
  171. }
  172. private void OnEnable()
  173. {
  174. RestoreNative();
  175. }
  176. private void OnDisable()
  177. {
  178. DestroyNative();
  179. }
  180. private void OnDestroy()
  181. {
  182. if (serializableData.bodies[0] != null)
  183. serializableData.bodies[0].SetJoint(null);
  184. if (serializableData.bodies[1] != null)
  185. serializableData.bodies[1].SetJoint(null);
  186. DestroyNative();
  187. }
  188. private void OnTransformChanged(TransformChangedFlags flags)
  189. {
  190. if (!SceneObject.Active)
  191. return;
  192. // We're ignoring this during physics update because it would cause problems if the joint itself was moved by physics
  193. // Note: This isn't particularily correct because if the joint is being moved by physics but the rigidbodies
  194. // themselves are not parented to the joint, the transform will need updating. However I'm leaving it up to the
  195. // user to ensure rigidbodies are always parented to the joint in such a case (It's an unlikely situation that
  196. // I can't think of an use for - joint transform will almost always be set as an initialization step and not a
  197. // physics response).
  198. if (Physics.IsUpdateInProgress)
  199. return;
  200. UpdateTransform(JointBody.A);
  201. UpdateTransform(JointBody.B);
  202. }
  203. /// <summary>
  204. /// Creates the internal representation of the Joint and restores the values saved by the Component.
  205. /// </summary>
  206. private void RestoreNative()
  207. {
  208. native = CreateNative();
  209. // Note: Merge into one call to avoid many virtual function calls
  210. Rigidbody[] bodies = new Rigidbody[2];
  211. if (serializableData.bodies[0] != null)
  212. bodies[0] = serializableData.bodies[0];
  213. else
  214. bodies[0] = null;
  215. if (serializableData.bodies[1] != null)
  216. bodies[1] = serializableData.bodies[1];
  217. else
  218. bodies[1] = null;
  219. native.SetRigidbody(JointBody.A, bodies[0]);
  220. native.SetRigidbody(JointBody.B, bodies[1]);
  221. native.BreakForce = serializableData.breakForce;
  222. native.BreakTorque = serializableData.breakTorque;
  223. native.EnableCollision = serializableData.enableCollision;
  224. native.BreakTorque = serializableData.breakTorque;
  225. native.EnableCollision = serializableData.enableCollision;
  226. UpdateTransform(JointBody.A);
  227. UpdateTransform(JointBody.B);
  228. }
  229. /// <summary>
  230. /// Destroys the internal joint representation.
  231. /// </summary>
  232. private void DestroyNative()
  233. {
  234. if (native != null)
  235. {
  236. native.Destroy();
  237. native = null;
  238. }
  239. }
  240. /// <summary>
  241. /// Updates the local transform for the specified body attached to the joint.
  242. /// </summary>
  243. /// <param name="body">Body to update.</param>
  244. private void UpdateTransform(JointBody body)
  245. {
  246. Vector3 localPos;
  247. Quaternion localRot;
  248. localPos = serializableData.positions[(int)body];
  249. localRot = serializableData.rotations[(int)body];
  250. // Transform to world space of the related body
  251. Rigidbody rigidbody = serializableData.bodies[(int)body];
  252. if (rigidbody != null)
  253. {
  254. localRot = rigidbody.SceneObject.Rotation * localRot;
  255. localPos = localRot.Rotate(localPos) + rigidbody.SceneObject.Position;
  256. }
  257. // Transform to space local to the joint
  258. Quaternion invRotation = SceneObject.Rotation.Inverse;
  259. localPos = invRotation.Rotate(localPos - SceneObject.Position);
  260. localRot = invRotation * localRot;
  261. native.SetPosition(body, localPos);
  262. native.SetRotation(body, localRot);
  263. }
  264. /// <summary>
  265. /// Holds all data the joint component needs to persist through serialization.
  266. /// </summary>
  267. [SerializeObject]
  268. internal class SerializableData
  269. {
  270. public Rigidbody[] bodies = new Rigidbody[2];
  271. public Vector3[] positions = new Vector3[2];
  272. public Quaternion[] rotations = new Quaternion[2];
  273. public float breakForce = float.MaxValue;
  274. public float breakTorque = float.MaxValue;
  275. public bool enableCollision = false;
  276. }
  277. }
  278. /// <summary>
  279. /// Controls spring parameters for a physics joint limits. If a limit is soft (body bounces back due to restitution when
  280. /// the limit is reached) the spring will pull the body back towards the limit using the specified parameters.
  281. /// </summary>
  282. [StructLayout(LayoutKind.Sequential), SerializeObject]
  283. public struct Spring // Note: Must match C++ struct Spring
  284. {
  285. /// <summary>
  286. /// Constructs a spring.
  287. /// </summary>
  288. /// <param name="stiffness">Spring strength.Force proportional to the position error.</param>
  289. /// <param name="damping">Damping strength. Force propertional to the velocity error.</param>
  290. public Spring(float stiffness, float damping)
  291. {
  292. this.stiffness = stiffness;
  293. this.damping = damping;
  294. }
  295. /// <inheritdoc/>
  296. public override bool Equals(object rhs)
  297. {
  298. if (rhs is Spring)
  299. {
  300. Spring other = (Spring)rhs;
  301. return stiffness == other.stiffness && damping == other.damping;
  302. }
  303. return false;
  304. }
  305. /// <inheritdoc/>
  306. public override int GetHashCode()
  307. {
  308. return base.GetHashCode();
  309. }
  310. public static bool operator ==(Spring a, Spring b)
  311. {
  312. return a.Equals(b);
  313. }
  314. public static bool operator !=(Spring a, Spring b)
  315. {
  316. return !(a == b);
  317. }
  318. /// <summary>
  319. /// Spring strength. Force proportional to the position error.
  320. /// </summary>
  321. public float stiffness;
  322. /// <summary>
  323. /// Damping strength. Force propertional to the velocity error.
  324. /// </summary>
  325. public float damping;
  326. }
  327. /// <summary>
  328. /// Specifies first or second body referenced by a Joint.
  329. /// </summary>
  330. public enum JointBody
  331. {
  332. A, B
  333. };
  334. /// <summary>
  335. /// Specifies axes that the D6 joint can constrain motion on.
  336. /// </summary>
  337. public enum D6JointAxis
  338. {
  339. /// <summary>
  340. /// Movement on the X axis.
  341. /// </summary>
  342. X,
  343. /// <summary>
  344. /// Movement on the Y axis.
  345. /// </summary>
  346. Y,
  347. /// <summary>
  348. /// Movement on the Z axis.
  349. /// </summary>
  350. Z,
  351. /// <summary>
  352. /// Rotation around the X axis.
  353. /// </summary>
  354. Twist,
  355. /// <summary>
  356. /// Rotation around the Y axis.
  357. /// </summary>
  358. SwingY,
  359. /// <summary>
  360. /// Rotation around the Z axis.
  361. /// </summary>
  362. SwingZ,
  363. Count
  364. }
  365. /// <summary>
  366. /// Specifies type of constraint placed on a specific axis of a D6 joint.
  367. /// </summary>
  368. public enum D6JointMotion
  369. {
  370. /// <summary>
  371. /// Axis is immovable.
  372. /// </summary>
  373. Locked,
  374. /// <summary>
  375. /// Axis will be constrained by the specified limits.
  376. /// </summary>
  377. Limited,
  378. /// <summary>
  379. /// Axis will not be constrained.
  380. /// </summary>
  381. Free,
  382. Count
  383. }
  384. /// <summary>
  385. /// Type of drives that can be used for moving or rotating bodies attached to the D6 joint.
  386. /// </summary>
  387. public enum D6JointDriveType
  388. {
  389. /// <summary>
  390. /// Linear movement on the X axis using the linear drive model.
  391. /// </summary>
  392. X,
  393. /// <summary>
  394. /// Linear movement on the Y axis using the linear drive model.
  395. /// </summary>
  396. Y,
  397. /// <summary>
  398. /// Linear movement on the Z axis using the linear drive model.
  399. /// </summary>
  400. Z,
  401. /// <summary>
  402. /// Rotation around the Y axis using the twist/swing angular drive model. Should not be used together with
  403. /// SLERP mode.
  404. /// </summary>
  405. Swing,
  406. /// <summary>
  407. /// Rotation around the Z axis using the twist/swing angular drive model. Should not be used together with
  408. /// SLERP mode.
  409. /// </summary>
  410. Twist,
  411. /// <summary>
  412. /// Rotation using spherical linear interpolation. Uses the SLERP angular drive mode which performs rotation
  413. /// by interpolating the quaternion values directly over the shortest path (applies to all three axes, which
  414. /// they all must be unlocked).
  415. /// </summary>
  416. SLERP,
  417. Count
  418. }
  419. /// <summary>
  420. /// Specifies parameters for a drive that will attempt to move the D6 joint bodies to the specified drive position and
  421. /// velocity.
  422. /// </summary>
  423. [SerializeObject]
  424. public class D6JointDrive
  425. {
  426. [SerializeField]
  427. private D6JointDriveData data;
  428. /// <summary>
  429. /// Spring strength. Force proportional to the position error.
  430. /// </summary>
  431. public float Stiffness { get { return data.stiffness; } }
  432. /// <summary>
  433. /// Damping strength. Force propertional to the velocity error.
  434. /// </summary>
  435. public float Damping { get { return data.damping; } }
  436. /// <summary>
  437. /// Maximum force the drive can apply.
  438. /// </summary>
  439. public float ForceLimit { get { return data.forceLimit; } }
  440. /// <summary>
  441. /// If true the drive will generate acceleration instead of forces. Acceleration drives are easier to tune as
  442. /// they account for the masses of the actors to which the joint is attached.
  443. /// </summary>
  444. public bool Acceleration { get { return data.acceleration; } }
  445. /// <summary>
  446. /// Gets drive properties.
  447. /// </summary>
  448. public D6JointDriveData Data
  449. {
  450. get { return data; }
  451. }
  452. /// <summary>
  453. /// Constructs a new D6 joint drive.
  454. /// </summary>
  455. /// <param name="stiffness"><see cref="Stiffness"/></param>
  456. /// <param name="damping"><see cref="Damping"/></param>
  457. /// <param name="forceLimit"><see cref="ForceLimit"/></param>
  458. /// <param name="acceleration"><see cref="Acceleration"/></param>
  459. public D6JointDrive(float stiffness = 0.0f, float damping = 0.0f, float forceLimit = float.MaxValue,
  460. bool acceleration = false)
  461. {
  462. data.stiffness = stiffness;
  463. data.damping = damping;
  464. data.forceLimit = forceLimit;
  465. data.acceleration = acceleration;
  466. }
  467. /// <summary>
  468. /// Constructs a new D6 joint drive.
  469. /// </summary>
  470. /// <param name="data">Properties to initialize the drive with.</param>
  471. public D6JointDrive(D6JointDriveData data)
  472. {
  473. this.data = data;
  474. }
  475. /// <inheritdoc/>
  476. public override bool Equals(object rhs)
  477. {
  478. if (rhs is D6JointDrive)
  479. {
  480. D6JointDrive other = (D6JointDrive)rhs;
  481. return Stiffness == other.Stiffness && Damping == other.Damping && ForceLimit == other.ForceLimit
  482. && Acceleration == other.Acceleration;
  483. }
  484. return false;
  485. }
  486. /// <inheritdoc/>
  487. public override int GetHashCode()
  488. {
  489. return base.GetHashCode();
  490. }
  491. public static bool operator ==(D6JointDrive a, D6JointDrive b)
  492. {
  493. return a.Equals(b);
  494. }
  495. public static bool operator !=(D6JointDrive a, D6JointDrive b)
  496. {
  497. return !(a == b);
  498. }
  499. /// <summary>
  500. /// Used for accessing drive data from native code.
  501. /// </summary>
  502. /// <param name="output">Native readable drive structure.</param>
  503. private void Internal_GetNative(out D6JointDriveData output)
  504. {
  505. output = data;
  506. }
  507. }
  508. /// <summary>
  509. /// Properties of a drive that drives the hinge joint's angular velocity towards a paricular value.
  510. /// </summary>
  511. [SerializeObject]
  512. public class HingeJointDrive
  513. {
  514. [SerializeField]
  515. private HingeJointDriveData data;
  516. /// <summary>
  517. /// Target speed of the joint.
  518. /// </summary>
  519. public float Speed { get { return data.speed; } }
  520. /// <summary>
  521. /// Maximum torque the drive is allowed to apply.
  522. /// </summary>
  523. public float ForceLimit { get { return data.forceLimit; } }
  524. /// <summary>
  525. /// Scales the velocity of the first body, and its response to drive torque is scaled down.
  526. /// </summary>
  527. public float GearRatio { get { return data.gearRatio; } }
  528. /// <summary>
  529. /// If the joint is moving faster than the drive's target speed, the drive will try to break. If you don't want
  530. /// the breaking to happen set this to true.
  531. /// </summary>
  532. public bool FreeSpin { get { return data.freeSpin; } }
  533. /// <summary>
  534. /// Gets drive properties.
  535. /// </summary>
  536. public HingeJointDriveData Data
  537. {
  538. get { return data; }
  539. }
  540. /// <summary>
  541. /// Constructs a new hinge joint drive.
  542. /// </summary>
  543. /// <param name="speed"><see cref="Speed"/></param>
  544. /// <param name="forceLimit"><see cref="ForceLimit"/></param>
  545. /// <param name="gearRatio"><see cref="GearRatio"/></param>
  546. /// <param name="freeSpin"><see cref="FreeSpin"/></param>
  547. public HingeJointDrive(float speed = 0.0f, float forceLimit = float.MaxValue,
  548. float gearRatio = 1.0f, bool freeSpin = false)
  549. {
  550. data.speed = speed;
  551. data.forceLimit = forceLimit;
  552. data.gearRatio = gearRatio;
  553. data.freeSpin = freeSpin;
  554. }
  555. /// <summary>
  556. /// Constructs a new hinge joint drive.
  557. /// </summary>
  558. /// <param name="data">Properties to initialize the drive with.</param>
  559. public HingeJointDrive(HingeJointDriveData data)
  560. {
  561. this.data = data;
  562. }
  563. /// <inheritdoc/>
  564. public override bool Equals(object rhs)
  565. {
  566. if (rhs is HingeJointDrive)
  567. {
  568. HingeJointDrive other = (HingeJointDrive)rhs;
  569. return data.speed == other.data.speed && data.gearRatio == other.data.gearRatio &&
  570. data.forceLimit == other.data.forceLimit && data.freeSpin == other.data.freeSpin;
  571. }
  572. return false;
  573. }
  574. /// <inheritdoc/>
  575. public override int GetHashCode()
  576. {
  577. return base.GetHashCode();
  578. }
  579. public static bool operator ==(HingeJointDrive a, HingeJointDrive b)
  580. {
  581. return a.Equals(b);
  582. }
  583. public static bool operator !=(HingeJointDrive a, HingeJointDrive b)
  584. {
  585. return !(a == b);
  586. }
  587. /// <summary>
  588. /// Used for accessing drive data from native code.
  589. /// </summary>
  590. /// <param name="output">Native readable drive structure.</param>
  591. private void Internal_GetNative(out HingeJointDriveData output)
  592. {
  593. output = data;
  594. }
  595. };
  596. /// <summary>
  597. /// Contains common values used by all Joint limit types.
  598. /// </summary>
  599. [SerializeObject]
  600. public class LimitCommon
  601. {
  602. private LimitCommonData data;
  603. /// <summary>
  604. /// Distance from the limit at which it becomes active. Allows the solver to activate earlier than the limit is
  605. /// reached to avoid breaking the limit.
  606. /// </summary>
  607. public float ContactDist { get { return data.contactDist; } }
  608. /// <summary>
  609. /// Controls how do objects react when the limit is reached, values closer to zero specify non-ellastic collision,
  610. /// while those closer to one specify more ellastic(i.e bouncy) collision.Must be in [0, 1] range.
  611. /// </summary>
  612. public float Restitution { get { return data.restitution; } }
  613. /// <summary>
  614. /// Spring that controls how are the bodies pulled back towards the limit when they breach it.
  615. /// </summary>
  616. public Spring Spring { get { return data.spring; } }
  617. /// <summary>
  618. /// Gets properties common to all limit types.
  619. /// </summary>
  620. public LimitCommonData CommonData
  621. {
  622. get { return data; }
  623. }
  624. protected LimitCommon(float contactDist = -1.0f)
  625. {
  626. data.contactDist = contactDist;
  627. data.restitution = 0.0f;
  628. data.spring = new Spring();
  629. }
  630. protected LimitCommon(Spring spring, float restitution = 0.0f)
  631. {
  632. data.contactDist = -1.0f;
  633. data.restitution = restitution;
  634. data.spring = spring;
  635. }
  636. protected LimitCommon(LimitCommonData data)
  637. {
  638. this.data = data;
  639. }
  640. /// <inheritdoc/>
  641. public override bool Equals(object rhs)
  642. {
  643. if (rhs is LimitCommon)
  644. {
  645. LimitCommon other = (LimitCommon)rhs;
  646. return ContactDist == other.ContactDist && Restitution == other.Restitution && Spring == other.Spring;
  647. }
  648. return false;
  649. }
  650. /// <inheritdoc/>
  651. public override int GetHashCode()
  652. {
  653. return base.GetHashCode();
  654. }
  655. public static bool operator ==(LimitCommon a, LimitCommon b)
  656. {
  657. return a.Equals(b);
  658. }
  659. public static bool operator !=(LimitCommon a, LimitCommon b)
  660. {
  661. return !(a == b);
  662. }
  663. }
  664. /// <summary>
  665. /// Represents a joint limit between two distance values. Lower value must be less than the upper value.
  666. /// </summary>
  667. [SerializeObject]
  668. public class LimitLinearRange : LimitCommon
  669. {
  670. private LimitLinearRangeData data;
  671. /// <summary>
  672. /// Lower distance of the limit. Must be less than <see cref="Upper"/>.
  673. /// </summary>
  674. public float Lower { get { return data.lower; } }
  675. /// <summary>
  676. /// Upper distance of the limit. Must be greater than <see cref="Lower"/>.
  677. /// </summary>
  678. public float Upper { get { return data.upper; } }
  679. /// <summary>
  680. /// Gets properties of the linear limit range.
  681. /// </summary>
  682. public LimitLinearRangeData Data
  683. {
  684. get { return data; }
  685. }
  686. /// <summary>
  687. /// Constructs an empty limit.
  688. /// </summary>
  689. public LimitLinearRange()
  690. { }
  691. /// <summary>
  692. /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
  693. /// </summary>
  694. /// <param name="lower"><see cref="Lower"/></param>
  695. /// <param name="upper"><see cref="Upper"/></param>
  696. /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
  697. public LimitLinearRange(float lower, float upper, float contactDist = -1.0f)
  698. :base(contactDist)
  699. {
  700. data.lower = lower;
  701. data.upper = upper;
  702. }
  703. /// <summary>
  704. /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
  705. /// parameter and will be pulled back towards the limit by the provided spring.
  706. /// </summary>
  707. /// <param name="lower"><see cref="Lower"/></param>
  708. /// <param name="upper"><see cref="Upper"/></param>
  709. /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
  710. /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
  711. public LimitLinearRange(float lower, float upper, Spring spring, float restitution = 0.0f)
  712. :base(spring, restitution)
  713. {
  714. data.lower = lower;
  715. data.upper = upper;
  716. }
  717. /// <summary>
  718. /// Constructs a new limit from the provided properties.
  719. /// </summary>
  720. /// <param name="limitData">Linear range specific properties.</param>
  721. /// <param name="commonData">Properties common to all limit types.</param>
  722. public LimitLinearRange(LimitLinearRangeData limitData, LimitCommonData commonData)
  723. :base(commonData)
  724. {
  725. this.data = limitData;
  726. }
  727. /// <inheritdoc/>
  728. public override bool Equals(object rhs)
  729. {
  730. if (rhs is LimitLinearRange)
  731. {
  732. LimitLinearRange other = (LimitLinearRange)rhs;
  733. return base.Equals(rhs) && Lower == other.Lower && Upper == other.Upper;
  734. }
  735. return false;
  736. }
  737. /// <inheritdoc/>
  738. public override int GetHashCode()
  739. {
  740. return base.GetHashCode();
  741. }
  742. public static bool operator ==(LimitLinearRange a, LimitLinearRange b)
  743. {
  744. return a.Equals(b);
  745. }
  746. public static bool operator !=(LimitLinearRange a, LimitLinearRange b)
  747. {
  748. return !(a == b);
  749. }
  750. /// <summary>
  751. /// Used for accessing limit data from native code.
  752. /// </summary>
  753. /// <param name="output">Native readable limit structure.</param>
  754. private void Internal_GetNative(ref ScriptLimitLinearRange output)
  755. {
  756. output.contactDist = ContactDist;
  757. output.restitution = Restitution;
  758. output.spring = Spring;
  759. output.lower = Lower;
  760. output.upper = Upper;
  761. }
  762. }
  763. /// <summary>
  764. /// Represents a joint limit between zero a single distance value.
  765. /// </summary>
  766. [SerializeObject]
  767. public class LimitLinear : LimitCommon
  768. {
  769. private LimitLinearData data;
  770. /// <summary>
  771. /// Distance at which the limit becomes active.
  772. /// </summary>
  773. public float Extent { get { return data.extent; } }
  774. /// <summary>
  775. /// Gets properties of the linear limit.
  776. /// </summary>
  777. public LimitLinearData Data
  778. {
  779. get { return data; }
  780. }
  781. /// <summary>
  782. /// Constructs an empty limit.
  783. /// </summary>
  784. public LimitLinear()
  785. { }
  786. /// <summary>
  787. /// Constructs a hard limit.Once the limit is reached the movement of the attached bodies will come to a stop.
  788. /// </summary>
  789. /// <param name="extent"><see cref="Extent"/></param>
  790. /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
  791. public LimitLinear(float extent, float contactDist = -1.0f)
  792. :base(contactDist)
  793. {
  794. data.extent = extent;
  795. }
  796. /// <summary>
  797. /// Constructs a soft limit.Once the limit is reached the bodies will bounce back according to the resitution
  798. /// parameter and will be pulled back towards the limit by the provided spring.
  799. /// </summary>
  800. /// <param name="extent"><see cref="Extent"/></param>
  801. /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
  802. /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
  803. public LimitLinear(float extent, Spring spring, float restitution = 0.0f)
  804. :base(spring, restitution)
  805. {
  806. data.extent = extent;
  807. }
  808. /// <summary>
  809. /// Constructs a new limit from the provided properties.
  810. /// </summary>
  811. /// <param name="limitData">Linear limit specific properties.</param>
  812. /// <param name="commonData">Properties common to all limit types.</param>
  813. public LimitLinear(LimitLinearData limitData, LimitCommonData commonData)
  814. :base(commonData)
  815. {
  816. this.data = limitData;
  817. }
  818. /// <inheritdoc/>
  819. public override bool Equals(object rhs)
  820. {
  821. if (rhs is LimitLinear)
  822. {
  823. LimitLinear other = (LimitLinear)rhs;
  824. return base.Equals(rhs) && Extent == other.Extent;
  825. }
  826. return false;
  827. }
  828. /// <inheritdoc/>
  829. public override int GetHashCode()
  830. {
  831. return base.GetHashCode();
  832. }
  833. public static bool operator ==(LimitLinear a, LimitLinear b)
  834. {
  835. return a.Equals(b);
  836. }
  837. public static bool operator !=(LimitLinear a, LimitLinear b)
  838. {
  839. return !(a == b);
  840. }
  841. /// <summary>
  842. /// Used for accessing limit data from native code.
  843. /// </summary>
  844. /// <param name="output">Native readable limit structure.</param>
  845. private void Internal_GetNative(ref ScriptLimitLinear output)
  846. {
  847. output.contactDist = ContactDist;
  848. output.restitution = Restitution;
  849. output.spring = Spring;
  850. output.extent = Extent;
  851. }
  852. }
  853. /// <summary>
  854. /// Represents a joint limit between two angles.
  855. /// </summary>
  856. [SerializeObject]
  857. public class LimitAngularRange : LimitCommon
  858. {
  859. private LimitAngularRangeData data;
  860. /// <summary>
  861. /// Lower angle of the limit. Must be less than <see cref="Upper"/>.
  862. /// </summary>
  863. public Radian Lower { get { return data.lower; } }
  864. /// <summary>
  865. /// Upper angle of the limit. Must be greater than <see cref="Lower"/>.
  866. /// </summary>
  867. public Radian Upper { get { return data.upper; } }
  868. /// <summary>
  869. /// Gets properties of the angular limit range.
  870. /// </summary>
  871. public LimitAngularRangeData Data
  872. {
  873. get { return data; }
  874. }
  875. /// <summary>
  876. /// Constructs an empty limit.
  877. /// </summary>
  878. public LimitAngularRange()
  879. { }
  880. /// <summary>
  881. /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
  882. /// </summary>
  883. /// <param name="lower"><see cref="Lower"/></param>
  884. /// <param name="upper"><see cref="Upper"/></param>
  885. /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
  886. public LimitAngularRange(Radian lower, Radian upper, float contactDist = -1.0f)
  887. : base(contactDist)
  888. {
  889. data.lower = lower;
  890. data.upper = upper;
  891. }
  892. /// <summary>
  893. /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
  894. /// parameter and will be pulled back towards the limit by the provided spring.
  895. /// </summary>
  896. /// <param name="lower"><see cref="Lower"/></param>
  897. /// <param name="upper"><see cref="Upper"/></param>
  898. /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
  899. /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
  900. public LimitAngularRange(Radian lower, Radian upper, Spring spring, float restitution = 0.0f)
  901. : base(spring, restitution)
  902. {
  903. data.lower = lower;
  904. data.upper = upper;
  905. }
  906. /// <summary>
  907. /// Constructs a new limit from the provided properties.
  908. /// </summary>
  909. /// <param name="limitData">Angular limit range specific properties.</param>
  910. /// <param name="commonData">Properties common to all limit types.</param>
  911. public LimitAngularRange(LimitAngularRangeData limitData, LimitCommonData commonData)
  912. :base(commonData)
  913. {
  914. this.data = limitData;
  915. }
  916. /// <inheritdoc/>
  917. public override bool Equals(object rhs)
  918. {
  919. if (rhs is LimitAngularRange)
  920. {
  921. LimitAngularRange other = (LimitAngularRange)rhs;
  922. return base.Equals(rhs) && Lower == other.Lower && Upper == other.Upper;
  923. }
  924. return false;
  925. }
  926. /// <inheritdoc/>
  927. public override int GetHashCode()
  928. {
  929. return base.GetHashCode();
  930. }
  931. public static bool operator ==(LimitAngularRange a, LimitAngularRange b)
  932. {
  933. return a.Equals(b);
  934. }
  935. public static bool operator !=(LimitAngularRange a, LimitAngularRange b)
  936. {
  937. return !(a == b);
  938. }
  939. /// <summary>
  940. /// Used for accessing limit data from native code.
  941. /// </summary>
  942. /// <param name="output">Native readable limit structure.</param>
  943. private void Internal_GetNative(ref ScriptLimitAngularRange output)
  944. {
  945. output.contactDist = ContactDist;
  946. output.restitution = Restitution;
  947. output.spring = Spring;
  948. output.lower = Lower;
  949. output.upper = Upper;
  950. }
  951. }
  952. /// <summary>
  953. /// Represents a joint limit that contraints movement to within an elliptical cone.
  954. /// </summary>
  955. [SerializeObject]
  956. public class LimitConeRange : LimitCommon
  957. {
  958. private LimitConeRangeData data;
  959. /// <summary>
  960. /// Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis.
  961. /// </summary>
  962. public Radian YLimitAngle { get { return data.yLimitAngle; } }
  963. /// <summary>
  964. /// Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis.
  965. /// </summary>
  966. public Radian ZLimitAngle { get { return data.zLimitAngle; } }
  967. /// <summary>
  968. /// Gets properties of the cone limit range.
  969. /// </summary>
  970. public LimitConeRangeData Data
  971. {
  972. get { return data; }
  973. }
  974. /// <summary>
  975. /// Constructs a limit with a 45 degree cone.
  976. /// </summary>
  977. public LimitConeRange()
  978. {
  979. data.yLimitAngle = new Radian(MathEx.Pi * 0.5f);
  980. data.zLimitAngle = new Radian(MathEx.Pi * 0.5f);
  981. }
  982. /// <summary>
  983. /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
  984. /// </summary>
  985. /// <param name="yLimitAngle"><see cref="YLimitAngle"/></param>
  986. /// <param name="zLimitAngle"><see cref="ZLimitAngle"/></param>
  987. /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
  988. public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, float contactDist = -1.0f)
  989. : base(contactDist)
  990. {
  991. data.yLimitAngle = yLimitAngle;
  992. data.zLimitAngle = zLimitAngle;
  993. }
  994. /// <summary>
  995. /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
  996. /// parameter and will be pulled back towards the limit by the provided spring.
  997. /// </summary>
  998. /// <param name="yLimitAngle"><see cref="YLimitAngle"/></param>
  999. /// <param name="zLimitAngle"><see cref="ZLimitAngle"/></param>
  1000. /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
  1001. /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
  1002. public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, Spring spring, float restitution = 0.0f)
  1003. : base(spring, restitution)
  1004. {
  1005. data.yLimitAngle = yLimitAngle;
  1006. data.zLimitAngle = zLimitAngle;
  1007. }
  1008. /// <summary>
  1009. /// Constructs a new limit from the provided properties.
  1010. /// </summary>
  1011. /// <param name="limitData">Cone limit range specific properties.</param>
  1012. /// <param name="commonData">Properties common to all limit types.</param>
  1013. public LimitConeRange(LimitConeRangeData limitData, LimitCommonData commonData)
  1014. :base(commonData)
  1015. {
  1016. this.data = limitData;
  1017. }
  1018. /// <inheritdoc/>
  1019. public override bool Equals(object rhs)
  1020. {
  1021. if (rhs is LimitConeRange)
  1022. {
  1023. LimitConeRange other = (LimitConeRange)rhs;
  1024. return base.Equals(rhs) && YLimitAngle == other.YLimitAngle && ZLimitAngle == other.ZLimitAngle;
  1025. }
  1026. return false;
  1027. }
  1028. /// <inheritdoc/>
  1029. public override int GetHashCode()
  1030. {
  1031. return base.GetHashCode();
  1032. }
  1033. public static bool operator ==(LimitConeRange a, LimitConeRange b)
  1034. {
  1035. return a.Equals(b);
  1036. }
  1037. public static bool operator !=(LimitConeRange a, LimitConeRange b)
  1038. {
  1039. return !(a == b);
  1040. }
  1041. /// <summary>
  1042. /// Used for accessing limit data from native code.
  1043. /// </summary>
  1044. /// <param name="output">Native readable limit structure.</param>
  1045. private void Internal_GetNative(ref ScriptLimitConeRange output)
  1046. {
  1047. output.contactDist = ContactDist;
  1048. output.restitution = Restitution;
  1049. output.spring = Spring;
  1050. output.yLimitAngle = YLimitAngle;
  1051. output.zLimitAngle = ZLimitAngle;
  1052. }
  1053. }
  1054. /// <summary>
  1055. /// Contains data used by HingeJointDrive.
  1056. /// </summary>
  1057. [StructLayout(LayoutKind.Sequential)]
  1058. public struct HingeJointDriveData // Note: Must match C++ struct HingeJoint::Drive
  1059. {
  1060. /// <summary>
  1061. /// <see cref="HingeJointDrive.Speed"/>
  1062. /// </summary>
  1063. public float speed;
  1064. /// <summary>
  1065. /// <see cref="HingeJointDrive.ForceLimit"/>
  1066. /// </summary>
  1067. public float forceLimit;
  1068. /// <summary>
  1069. /// <see cref="HingeJointDrive.GearRatio"/>
  1070. /// </summary>
  1071. public float gearRatio;
  1072. /// <summary>
  1073. /// <see cref="HingeJointDrive.FreeSpin"/>
  1074. /// </summary>
  1075. public bool freeSpin;
  1076. }
  1077. /// <summary>
  1078. /// Contains data used by D6JointDrive.
  1079. /// </summary>
  1080. [StructLayout(LayoutKind.Sequential)]
  1081. public struct D6JointDriveData // Note: Must match C++ struct D6Joint::Drive
  1082. {
  1083. /// <summary>
  1084. /// <see cref="D6JointDrive.Stiffness"/>
  1085. /// </summary>
  1086. public float stiffness;
  1087. /// <summary>
  1088. /// <see cref="D6JointDrive.Damping"/>
  1089. /// </summary>
  1090. public float damping;
  1091. /// <summary>
  1092. /// <see cref="D6JointDrive.ForceLimit"/>
  1093. /// </summary>
  1094. public float forceLimit;
  1095. /// <summary>
  1096. /// <see cref="D6JointDrive.Acceleration"/>
  1097. /// </summary>
  1098. public bool acceleration;
  1099. }
  1100. /// <summary>
  1101. /// Contains data used by LimitCommon.
  1102. /// </summary>
  1103. public struct LimitCommonData
  1104. {
  1105. /// <summary>
  1106. /// <see cref="LimitCommon.ContactDist"/>
  1107. /// </summary>
  1108. public float contactDist;
  1109. /// <summary>
  1110. /// <see cref="LimitCommon.Restitution"/>
  1111. /// </summary>
  1112. public float restitution;
  1113. /// <summary>
  1114. /// <see cref="LimitCommon.Spring"/>
  1115. /// </summary>
  1116. public Spring spring;
  1117. }
  1118. /// <summary>
  1119. /// Contains data used by LimitLinearRange.
  1120. /// </summary>
  1121. public struct LimitLinearRangeData
  1122. {
  1123. /// <summary>
  1124. /// <see cref="LimitLinearRange.Lower"/>
  1125. /// </summary>
  1126. public float lower;
  1127. /// <summary>
  1128. /// <see cref="LimitLinearRange.Upper"/>
  1129. /// </summary>
  1130. public float upper;
  1131. }
  1132. /// <summary>
  1133. /// Contains data used by LimitLinear.
  1134. /// </summary>
  1135. public struct LimitLinearData
  1136. {
  1137. /// <summary>
  1138. /// <see cref="LimitLinearRange.Extent"/>
  1139. /// </summary>
  1140. public float extent;
  1141. }
  1142. /// <summary>
  1143. /// Contains data used by LimitAngularRange.
  1144. /// </summary>
  1145. public struct LimitAngularRangeData
  1146. {
  1147. /// <summary>
  1148. /// <see cref="LimitAngularRange.Lower"/>
  1149. /// </summary>
  1150. public Radian lower;
  1151. /// <summary>
  1152. /// <see cref="LimitAngularRange.Upper"/>
  1153. /// </summary>
  1154. public Radian upper;
  1155. }
  1156. /// <summary>
  1157. /// Contains data used by LimitConeRange.
  1158. /// </summary>
  1159. public struct LimitConeRangeData
  1160. {
  1161. /// <summary>
  1162. /// <see cref="LimitConeRange.YLimitAngle"/>
  1163. /// </summary>
  1164. public Radian yLimitAngle;
  1165. /// <summary>
  1166. /// <see cref="LimitConeRange.ZLimitAngle"/>
  1167. /// </summary>
  1168. public Radian zLimitAngle;
  1169. }
  1170. /// <summary>
  1171. /// Used for passing LimitLinearRange data between native and managed code.
  1172. /// </summary>
  1173. [StructLayout(LayoutKind.Sequential)]
  1174. internal struct ScriptLimitLinearRange // Note: Must match C++ struct LimitLinearRange
  1175. {
  1176. public float contactDist;
  1177. public float restitution;
  1178. public Spring spring;
  1179. public float lower;
  1180. public float upper;
  1181. }
  1182. /// <summary>
  1183. /// Used for passing LimitLinear data between native and managed code.
  1184. /// </summary>
  1185. [StructLayout(LayoutKind.Sequential)]
  1186. internal struct ScriptLimitLinear // Note: Must match C++ struct LimitLinear
  1187. {
  1188. public float contactDist;
  1189. public float restitution;
  1190. public Spring spring;
  1191. public float extent;
  1192. }
  1193. /// <summary>
  1194. /// Used for passing LimitAngularRange data between native and managed code.
  1195. /// </summary>
  1196. [StructLayout(LayoutKind.Sequential)]
  1197. internal struct ScriptLimitAngularRange // Note: Must match C++ struct LimitAngularRange
  1198. {
  1199. public float contactDist;
  1200. public float restitution;
  1201. public Spring spring;
  1202. public Radian lower;
  1203. public Radian upper;
  1204. }
  1205. /// <summary>
  1206. /// Used for passing LimitConeRange data between native and managed code.
  1207. /// </summary>
  1208. [StructLayout(LayoutKind.Sequential)]
  1209. internal struct ScriptLimitConeRange // Note: Must match C++ struct LimitConeRange
  1210. {
  1211. public float contactDist;
  1212. public float restitution;
  1213. public Spring spring;
  1214. public Radian yLimitAngle;
  1215. public Radian zLimitAngle;
  1216. }
  1217. }