8 using UnityEngine.Events;
9 using System.Collections;
11 namespace Valve.VR.InteractionSystem
14 [RequireComponent( typeof( Interactable ) )]
15 [RequireComponent( typeof( Rigidbody ) )]
16 [RequireComponent( typeof( VelocityEstimator ) )]
20 [Tooltip(
"The flags used to attach this object to the hand." )]
21 public Hand.AttachmentFlags attachmentFlags = Hand.AttachmentFlags.ParentToHand | Hand.AttachmentFlags.DetachFromOtherHand;
23 [Tooltip(
"Name of the attachment transform under in the hand's hierarchy which the object should should snap to." )]
24 public string attachmentPoint;
26 [Tooltip(
"How fast must this object be moving to attach due to a trigger hold instead of a trigger press?" )]
27 public float catchSpeedThreshold = 0.0f;
29 [Tooltip(
"When detaching the object, should it return to its original parent?" )]
30 public bool restoreOriginalParent =
false;
32 public bool attachEaseIn =
false;
33 public AnimationCurve snapAttachEaseInCurve = AnimationCurve.EaseInOut( 0.0f, 0.0f, 1.0f, 1.0f );
34 public float snapAttachEaseInTime = 0.15f;
35 public string[] attachEaseInAttachmentNames;
38 private bool attached =
false;
39 private float attachTime;
40 private Vector3 attachPosition;
41 private Quaternion attachRotation;
42 private Transform attachEaseInTransform;
44 public UnityEvent onPickUp;
45 public UnityEvent onDetachFromHand;
47 public bool snapAttachEaseInCompleted =
false;
53 velocityEstimator = GetComponent<VelocityEstimator>();
57 attachmentFlags &= ~
Hand.AttachmentFlags.SnapOnAttach;
60 Rigidbody rb = GetComponent<Rigidbody>();
61 rb.maxAngularVelocity = 50.0f;
66 private void OnHandHoverBegin(
Hand hand )
68 bool showHint =
false;
75 if ( hand.GetStandardInteractionButton() )
77 Rigidbody rb = GetComponent<Rigidbody>();
78 if ( rb.velocity.magnitude >= catchSpeedThreshold )
80 hand.AttachObject( gameObject, attachmentFlags, attachmentPoint );
88 ControllerButtonHints.ShowButtonHint( hand, Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger );
94 private void OnHandHoverEnd(
Hand hand )
96 ControllerButtonHints.HideButtonHint( hand, Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger );
101 private void HandHoverUpdate(
Hand hand )
104 if ( hand.GetStandardInteractionButtonDown() )
106 hand.AttachObject( gameObject, attachmentFlags, attachmentPoint );
107 ControllerButtonHints.HideButtonHint( hand, Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger );
112 private void OnAttachedToHand(
Hand hand )
118 hand.HoverLock( null );
120 Rigidbody rb = GetComponent<Rigidbody>();
121 rb.isKinematic =
true;
122 rb.interpolation = RigidbodyInterpolation.None;
124 if ( hand.controller == null )
126 velocityEstimator.BeginEstimatingVelocity();
129 attachTime = Time.time;
130 attachPosition = transform.position;
131 attachRotation = transform.rotation;
135 attachEaseInTransform = hand.transform;
136 if ( !Util.IsNullOrEmpty( attachEaseInAttachmentNames ) )
138 float smallestAngle = float.MaxValue;
139 for (
int i = 0; i < attachEaseInAttachmentNames.Length; i++ )
141 Transform t = hand.GetAttachmentTransform( attachEaseInAttachmentNames[i] );
142 float angle = Quaternion.Angle( t.rotation, attachRotation );
143 if ( angle < smallestAngle )
145 attachEaseInTransform = t;
146 smallestAngle = angle;
152 snapAttachEaseInCompleted =
false;
157 private void OnDetachedFromHand(
Hand hand )
161 onDetachFromHand.Invoke();
163 hand.HoverUnlock( null );
165 Rigidbody rb = GetComponent<Rigidbody>();
166 rb.isKinematic =
false;
167 rb.interpolation = RigidbodyInterpolation.Interpolate;
169 Vector3 position = Vector3.zero;
170 Vector3 velocity = Vector3.zero;
171 Vector3 angularVelocity = Vector3.zero;
172 if ( hand.controller == null )
174 velocityEstimator.FinishEstimatingVelocity();
175 velocity = velocityEstimator.GetVelocityEstimate();
176 angularVelocity = velocityEstimator.GetAngularVelocityEstimate();
177 position = velocityEstimator.transform.position;
181 velocity = Player.instance.trackingOriginTransform.TransformVector( hand.controller.velocity );
182 angularVelocity = Player.instance.trackingOriginTransform.TransformVector( hand.controller.angularVelocity );
183 position = hand.transform.position;
186 Vector3 r = transform.TransformPoint( rb.centerOfMass ) - position;
187 rb.velocity = velocity + Vector3.Cross( angularVelocity, r );
188 rb.angularVelocity = angularVelocity;
193 float timeUntilFixedUpdate = ( Time.fixedDeltaTime + Time.fixedTime ) - Time.time;
194 transform.position += timeUntilFixedUpdate * velocity;
195 float angle = Mathf.Rad2Deg * angularVelocity.magnitude;
196 Vector3 axis = angularVelocity.normalized;
197 transform.rotation *= Quaternion.AngleAxis( angle * timeUntilFixedUpdate, axis );
202 private void HandAttachedUpdate(
Hand hand )
205 if ( !hand.GetStandardInteractionButton() )
213 StartCoroutine( LateDetach( hand ) );
218 float t = Util.RemapNumberClamped( Time.time, attachTime, attachTime + snapAttachEaseInTime, 0.0f, 1.0f );
221 t = snapAttachEaseInCurve.Evaluate( t );
222 transform.position = Vector3.Lerp( attachPosition, attachEaseInTransform.position, t );
223 transform.rotation = Quaternion.Lerp( attachRotation, attachEaseInTransform.rotation, t );
225 else if ( !snapAttachEaseInCompleted )
227 gameObject.SendMessage(
"OnThrowableAttachEaseInCompleted", hand, SendMessageOptions.DontRequireReceiver );
228 snapAttachEaseInCompleted =
true;
235 private IEnumerator LateDetach(
Hand hand )
237 yield
return new WaitForEndOfFrame();
239 hand.DetachObject( gameObject, restoreOriginalParent );
244 private void OnHandFocusAcquired(
Hand hand )
246 gameObject.SetActive( true );
247 velocityEstimator.BeginEstimatingVelocity();
252 private void OnHandFocusLost(
Hand hand )
254 gameObject.SetActive( false );
255 velocityEstimator.FinishEstimatingVelocity();