Throwable.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Basic throwable object
  4. //
  5. //=============================================================================
  6. using UnityEngine;
  7. using UnityEngine.Events;
  8. using System.Collections;
  9. namespace Valve.VR.InteractionSystem
  10. {
  11. //-------------------------------------------------------------------------
  12. [RequireComponent( typeof( Interactable ) )]
  13. [RequireComponent( typeof( Rigidbody ) )]
  14. [RequireComponent( typeof( VelocityEstimator ) )]
  15. public class Throwable : MonoBehaviour
  16. {
  17. [EnumFlags]
  18. [Tooltip( "The flags used to attach this object to the hand." )]
  19. public Hand.AttachmentFlags attachmentFlags = Hand.AttachmentFlags.ParentToHand | Hand.AttachmentFlags.DetachFromOtherHand;
  20. [Tooltip( "Name of the attachment transform under in the hand's hierarchy which the object should should snap to." )]
  21. public string attachmentPoint;
  22. [Tooltip( "How fast must this object be moving to attach due to a trigger hold instead of a trigger press?" )]
  23. public float catchSpeedThreshold = 0.0f;
  24. [Tooltip( "When detaching the object, should it return to its original parent?" )]
  25. public bool restoreOriginalParent = false;
  26. public bool attachEaseIn = false;
  27. public AnimationCurve snapAttachEaseInCurve = AnimationCurve.EaseInOut( 0.0f, 0.0f, 1.0f, 1.0f );
  28. public float snapAttachEaseInTime = 0.15f;
  29. public string[] attachEaseInAttachmentNames;
  30. private VelocityEstimator velocityEstimator;
  31. private bool attached = false;
  32. private float attachTime;
  33. private Vector3 attachPosition;
  34. private Quaternion attachRotation;
  35. private Transform attachEaseInTransform;
  36. public UnityEvent onPickUp;
  37. public UnityEvent onDetachFromHand;
  38. public bool snapAttachEaseInCompleted = false;
  39. //-------------------------------------------------
  40. void Awake()
  41. {
  42. velocityEstimator = GetComponent<VelocityEstimator>();
  43. if ( attachEaseIn )
  44. {
  45. attachmentFlags &= ~Hand.AttachmentFlags.SnapOnAttach;
  46. }
  47. Rigidbody rb = GetComponent<Rigidbody>();
  48. rb.maxAngularVelocity = 50.0f;
  49. }
  50. //-------------------------------------------------
  51. private void OnHandHoverBegin( Hand hand )
  52. {
  53. bool showHint = false;
  54. // "Catch" the throwable by holding down the interaction button instead of pressing it.
  55. // Only do this if the throwable is moving faster than the prescribed threshold speed,
  56. // and if it isn't attached to another hand
  57. if ( !attached )
  58. {
  59. if ( hand.GetStandardInteractionButton() )
  60. {
  61. Rigidbody rb = GetComponent<Rigidbody>();
  62. if ( rb.velocity.magnitude >= catchSpeedThreshold )
  63. {
  64. hand.AttachObject( gameObject, attachmentFlags, attachmentPoint );
  65. showHint = false;
  66. }
  67. }
  68. }
  69. if ( showHint )
  70. {
  71. ControllerButtonHints.ShowButtonHint( hand, Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger );
  72. }
  73. }
  74. //-------------------------------------------------
  75. private void OnHandHoverEnd( Hand hand )
  76. {
  77. ControllerButtonHints.HideButtonHint( hand, Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger );
  78. }
  79. //-------------------------------------------------
  80. private void HandHoverUpdate( Hand hand )
  81. {
  82. //Trigger got pressed
  83. if ( hand.GetStandardInteractionButtonDown() )
  84. {
  85. hand.AttachObject( gameObject, attachmentFlags, attachmentPoint );
  86. ControllerButtonHints.HideButtonHint( hand, Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger );
  87. }
  88. }
  89. //-------------------------------------------------
  90. private void OnAttachedToHand( Hand hand )
  91. {
  92. attached = true;
  93. onPickUp.Invoke();
  94. hand.HoverLock( null );
  95. Rigidbody rb = GetComponent<Rigidbody>();
  96. rb.isKinematic = true;
  97. rb.interpolation = RigidbodyInterpolation.None;
  98. if ( hand.controller == null )
  99. {
  100. velocityEstimator.BeginEstimatingVelocity();
  101. }
  102. attachTime = Time.time;
  103. attachPosition = transform.position;
  104. attachRotation = transform.rotation;
  105. if ( attachEaseIn )
  106. {
  107. attachEaseInTransform = hand.transform;
  108. if ( !Util.IsNullOrEmpty( attachEaseInAttachmentNames ) )
  109. {
  110. float smallestAngle = float.MaxValue;
  111. for ( int i = 0; i < attachEaseInAttachmentNames.Length; i++ )
  112. {
  113. Transform t = hand.GetAttachmentTransform( attachEaseInAttachmentNames[i] );
  114. float angle = Quaternion.Angle( t.rotation, attachRotation );
  115. if ( angle < smallestAngle )
  116. {
  117. attachEaseInTransform = t;
  118. smallestAngle = angle;
  119. }
  120. }
  121. }
  122. }
  123. snapAttachEaseInCompleted = false;
  124. }
  125. //-------------------------------------------------
  126. private void OnDetachedFromHand( Hand hand )
  127. {
  128. attached = false;
  129. onDetachFromHand.Invoke();
  130. hand.HoverUnlock( null );
  131. Rigidbody rb = GetComponent<Rigidbody>();
  132. rb.isKinematic = false;
  133. rb.interpolation = RigidbodyInterpolation.Interpolate;
  134. Vector3 position = Vector3.zero;
  135. Vector3 velocity = Vector3.zero;
  136. Vector3 angularVelocity = Vector3.zero;
  137. if ( hand.controller == null )
  138. {
  139. velocityEstimator.FinishEstimatingVelocity();
  140. velocity = velocityEstimator.GetVelocityEstimate();
  141. angularVelocity = velocityEstimator.GetAngularVelocityEstimate();
  142. position = velocityEstimator.transform.position;
  143. }
  144. else
  145. {
  146. velocity = Player.instance.trackingOriginTransform.TransformVector( hand.controller.velocity );
  147. angularVelocity = Player.instance.trackingOriginTransform.TransformVector( hand.controller.angularVelocity );
  148. position = hand.transform.position;
  149. }
  150. Vector3 r = transform.TransformPoint( rb.centerOfMass ) - position;
  151. rb.velocity = velocity + Vector3.Cross( angularVelocity, r );
  152. rb.angularVelocity = angularVelocity;
  153. // Make the object travel at the release velocity for the amount
  154. // of time it will take until the next fixed update, at which
  155. // point Unity physics will take over
  156. float timeUntilFixedUpdate = ( Time.fixedDeltaTime + Time.fixedTime ) - Time.time;
  157. transform.position += timeUntilFixedUpdate * velocity;
  158. float angle = Mathf.Rad2Deg * angularVelocity.magnitude;
  159. Vector3 axis = angularVelocity.normalized;
  160. transform.rotation *= Quaternion.AngleAxis( angle * timeUntilFixedUpdate, axis );
  161. }
  162. //-------------------------------------------------
  163. private void HandAttachedUpdate( Hand hand )
  164. {
  165. //Trigger got released
  166. if ( !hand.GetStandardInteractionButton() )
  167. {
  168. // Detach ourselves late in the frame.
  169. // This is so that any vehicles the player is attached to
  170. // have a chance to finish updating themselves.
  171. // If we detach now, our position could be behind what it
  172. // will be at the end of the frame, and the object may appear
  173. // to teleport behind the hand when the player releases it.
  174. StartCoroutine( LateDetach( hand ) );
  175. }
  176. if ( attachEaseIn )
  177. {
  178. float t = Util.RemapNumberClamped( Time.time, attachTime, attachTime + snapAttachEaseInTime, 0.0f, 1.0f );
  179. if ( t < 1.0f )
  180. {
  181. t = snapAttachEaseInCurve.Evaluate( t );
  182. transform.position = Vector3.Lerp( attachPosition, attachEaseInTransform.position, t );
  183. transform.rotation = Quaternion.Lerp( attachRotation, attachEaseInTransform.rotation, t );
  184. }
  185. else if ( !snapAttachEaseInCompleted )
  186. {
  187. gameObject.SendMessage( "OnThrowableAttachEaseInCompleted", hand, SendMessageOptions.DontRequireReceiver );
  188. snapAttachEaseInCompleted = true;
  189. }
  190. }
  191. }
  192. //-------------------------------------------------
  193. private IEnumerator LateDetach( Hand hand )
  194. {
  195. yield return new WaitForEndOfFrame();
  196. hand.DetachObject( gameObject, restoreOriginalParent );
  197. }
  198. //-------------------------------------------------
  199. private void OnHandFocusAcquired( Hand hand )
  200. {
  201. gameObject.SetActive( true );
  202. velocityEstimator.BeginEstimatingVelocity();
  203. }
  204. //-------------------------------------------------
  205. private void OnHandFocusLost( Hand hand )
  206. {
  207. gameObject.SetActive( false );
  208. velocityEstimator.FinishEstimatingVelocity();
  209. }
  210. }
  211. }