Throwable.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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. public class Throwable : MonoBehaviour
  15. {
  16. [EnumFlags]
  17. [Tooltip( "The flags used to attach this object to the hand." )]
  18. public Hand.AttachmentFlags attachmentFlags = Hand.AttachmentFlags.ParentToHand | Hand.AttachmentFlags.DetachFromOtherHand | Hand.AttachmentFlags.TurnOnKinematic;
  19. [Tooltip("The local point which acts as a positional and rotational offset to use while held")]
  20. public Transform attachmentOffset;
  21. [Tooltip( "How fast must this object be moving to attach due to a trigger hold instead of a trigger press? (-1 to disable)" )]
  22. public float catchingSpeedThreshold = -1;
  23. public ReleaseStyle releaseVelocityStyle = ReleaseStyle.GetFromHand;
  24. [Tooltip("The time offset used when releasing the object with the RawFromHand option")]
  25. public float releaseVelocityTimeOffset = -0.011f;
  26. public float scaleReleaseVelocity = 1.1f;
  27. [Tooltip("The release velocity magnitude representing the end of the scale release velocity curve. (-1 to disable)")]
  28. public float scaleReleaseVelocityThreshold = -1.0f;
  29. [Tooltip("Use this curve to ease into the scaled release velocity based on the magnitude of the measured release velocity. This allows greater differentiation between a drop, toss, and throw.")]
  30. public AnimationCurve scaleReleaseVelocityCurve = AnimationCurve.EaseInOut(0.0f, 0.1f, 1.0f, 1.0f);
  31. [Tooltip( "When detaching the object, should it return to its original parent?" )]
  32. public bool restoreOriginalParent = false;
  33. protected VelocityEstimator velocityEstimator;
  34. protected bool attached = false;
  35. protected float attachTime;
  36. protected Vector3 attachPosition;
  37. protected Quaternion attachRotation;
  38. protected Transform attachEaseInTransform;
  39. public UnityEvent onPickUp;
  40. public UnityEvent onDetachFromHand;
  41. public HandEvent onHeldUpdate;
  42. protected RigidbodyInterpolation hadInterpolation = RigidbodyInterpolation.None;
  43. protected new Rigidbody rigidbody;
  44. [HideInInspector]
  45. public Interactable interactable;
  46. //-------------------------------------------------
  47. protected virtual void Awake()
  48. {
  49. velocityEstimator = GetComponent<VelocityEstimator>();
  50. interactable = GetComponent<Interactable>();
  51. rigidbody = GetComponent<Rigidbody>();
  52. rigidbody.maxAngularVelocity = 50.0f;
  53. if(attachmentOffset != null)
  54. {
  55. // remove?
  56. //interactable.handFollowTransform = attachmentOffset;
  57. }
  58. }
  59. //-------------------------------------------------
  60. protected virtual void OnHandHoverBegin( Hand hand )
  61. {
  62. bool showHint = false;
  63. // "Catch" the throwable by holding down the interaction button instead of pressing it.
  64. // Only do this if the throwable is moving faster than the prescribed threshold speed,
  65. // and if it isn't attached to another hand
  66. if ( !attached && catchingSpeedThreshold != -1)
  67. {
  68. float catchingThreshold = catchingSpeedThreshold * SteamVR_Utils.GetLossyScale(Player.instance.trackingOriginTransform);
  69. GrabTypes bestGrabType = hand.GetBestGrabbingType();
  70. if ( bestGrabType != GrabTypes.None )
  71. {
  72. if (rigidbody.velocity.magnitude >= catchingThreshold)
  73. {
  74. hand.AttachObject( gameObject, bestGrabType, attachmentFlags );
  75. showHint = false;
  76. }
  77. }
  78. }
  79. if ( showHint )
  80. {
  81. hand.ShowGrabHint();
  82. }
  83. }
  84. //-------------------------------------------------
  85. protected virtual void OnHandHoverEnd( Hand hand )
  86. {
  87. hand.HideGrabHint();
  88. }
  89. //-------------------------------------------------
  90. protected virtual void HandHoverUpdate( Hand hand )
  91. {
  92. GrabTypes startingGrabType = hand.GetGrabStarting();
  93. if (startingGrabType != GrabTypes.None)
  94. {
  95. hand.AttachObject( gameObject, startingGrabType, attachmentFlags, attachmentOffset );
  96. hand.HideGrabHint();
  97. }
  98. }
  99. //-------------------------------------------------
  100. protected virtual void OnAttachedToHand( Hand hand )
  101. {
  102. //Debug.Log("<b>[SteamVR Interaction]</b> Pickup: " + hand.GetGrabStarting().ToString());
  103. hadInterpolation = this.rigidbody.interpolation;
  104. attached = true;
  105. onPickUp.Invoke();
  106. hand.HoverLock( null );
  107. rigidbody.interpolation = RigidbodyInterpolation.None;
  108. if (velocityEstimator != null)
  109. velocityEstimator.BeginEstimatingVelocity();
  110. attachTime = Time.time;
  111. attachPosition = transform.position;
  112. attachRotation = transform.rotation;
  113. }
  114. //-------------------------------------------------
  115. protected virtual void OnDetachedFromHand(Hand hand)
  116. {
  117. attached = false;
  118. onDetachFromHand.Invoke();
  119. hand.HoverUnlock(null);
  120. rigidbody.interpolation = hadInterpolation;
  121. Vector3 velocity;
  122. Vector3 angularVelocity;
  123. GetReleaseVelocities(hand, out velocity, out angularVelocity);
  124. rigidbody.velocity = velocity;
  125. rigidbody.angularVelocity = angularVelocity;
  126. }
  127. public virtual void GetReleaseVelocities(Hand hand, out Vector3 velocity, out Vector3 angularVelocity)
  128. {
  129. if (hand.noSteamVRFallbackCamera && releaseVelocityStyle != ReleaseStyle.NoChange)
  130. releaseVelocityStyle = ReleaseStyle.ShortEstimation; // only type that works with fallback hand is short estimation.
  131. switch (releaseVelocityStyle)
  132. {
  133. case ReleaseStyle.ShortEstimation:
  134. if (velocityEstimator != null)
  135. {
  136. velocityEstimator.FinishEstimatingVelocity();
  137. velocity = velocityEstimator.GetVelocityEstimate();
  138. angularVelocity = velocityEstimator.GetAngularVelocityEstimate();
  139. }
  140. else
  141. {
  142. Debug.LogWarning("[SteamVR Interaction System] Throwable: No Velocity Estimator component on object but release style set to short estimation. Please add one or change the release style.");
  143. velocity = rigidbody.velocity;
  144. angularVelocity = rigidbody.angularVelocity;
  145. }
  146. break;
  147. case ReleaseStyle.AdvancedEstimation:
  148. hand.GetEstimatedPeakVelocities(out velocity, out angularVelocity);
  149. break;
  150. case ReleaseStyle.GetFromHand:
  151. velocity = hand.GetTrackedObjectVelocity(releaseVelocityTimeOffset);
  152. angularVelocity = hand.GetTrackedObjectAngularVelocity(releaseVelocityTimeOffset);
  153. break;
  154. default:
  155. case ReleaseStyle.NoChange:
  156. velocity = rigidbody.velocity;
  157. angularVelocity = rigidbody.angularVelocity;
  158. break;
  159. }
  160. if (releaseVelocityStyle != ReleaseStyle.NoChange)
  161. {
  162. float scaleFactor = 1.0f;
  163. if (scaleReleaseVelocityThreshold > 0)
  164. {
  165. scaleFactor = Mathf.Clamp01(scaleReleaseVelocityCurve.Evaluate(velocity.magnitude / scaleReleaseVelocityThreshold));
  166. }
  167. velocity *= (scaleFactor * scaleReleaseVelocity);
  168. }
  169. }
  170. //-------------------------------------------------
  171. protected virtual void HandAttachedUpdate(Hand hand)
  172. {
  173. if (hand.IsGrabEnding(this.gameObject))
  174. {
  175. hand.DetachObject(gameObject, restoreOriginalParent);
  176. // Uncomment to detach ourselves late in the frame.
  177. // This is so that any vehicles the player is attached to
  178. // have a chance to finish updating themselves.
  179. // If we detach now, our position could be behind what it
  180. // will be at the end of the frame, and the object may appear
  181. // to teleport behind the hand when the player releases it.
  182. //StartCoroutine( LateDetach( hand ) );
  183. }
  184. if (onHeldUpdate != null)
  185. onHeldUpdate.Invoke(hand);
  186. }
  187. //-------------------------------------------------
  188. protected virtual IEnumerator LateDetach( Hand hand )
  189. {
  190. yield return new WaitForEndOfFrame();
  191. hand.DetachObject( gameObject, restoreOriginalParent );
  192. }
  193. //-------------------------------------------------
  194. protected virtual void OnHandFocusAcquired( Hand hand )
  195. {
  196. gameObject.SetActive( true );
  197. if (velocityEstimator != null)
  198. velocityEstimator.BeginEstimatingVelocity();
  199. }
  200. //-------------------------------------------------
  201. protected virtual void OnHandFocusLost( Hand hand )
  202. {
  203. gameObject.SetActive( false );
  204. if (velocityEstimator != null)
  205. velocityEstimator.FinishEstimatingVelocity();
  206. }
  207. }
  208. public enum ReleaseStyle
  209. {
  210. NoChange,
  211. GetFromHand,
  212. ShortEstimation,
  213. AdvancedEstimation,
  214. }
  215. }