8 using System.Collections;
9 using System.Collections.Generic;
11 namespace Valve.VR.InteractionSystem
14 [RequireComponent( typeof( Interactable ) )]
17 public enum Handedness { Left, Right };
19 public Handedness currentHandGuess = Handedness.Left;
20 private float timeOfPossibleHandSwitch = 0f;
21 private float timeBeforeConfirmingHandSwitch = 1.5f;
22 private bool possibleHandSwitch =
false;
24 public Transform pivotTransform;
25 public Transform handleTransform;
30 public Transform nockTransform;
31 public Transform nockRestTransform;
33 public bool autoSpawnArrowHand =
true;
35 public GameObject arrowHandPrefab;
40 private const float minPull = 0.05f;
41 private const float maxPull = 0.5f;
42 private float nockDistanceTravelled = 0f;
43 private float hapticDistanceThreshold = 0.01f;
44 private float lastTickDistance;
45 private const float bowPullPulseStrengthLow = 100;
46 private const float bowPullPulseStrengthHigh = 500;
47 private Vector3 bowLeftVector;
49 public float arrowMinVelocity = 3f;
50 public float arrowMaxVelocity = 30f;
51 private float arrowVelocity = 30f;
53 private float minStrainTickTime = 0.1f;
54 private float maxStrainTickTime = 0.5f;
55 private float nextStrainTick = 0;
57 private bool lerpBackToZeroRotation;
58 private float lerpStartTime;
59 private float lerpDuration = 0.15f;
60 private Quaternion lerpStartRotation;
62 private float nockLerpStartTime;
64 private Quaternion nockLerpStartRotation;
66 public float drawOffset = 0.06f;
70 private bool deferNewPoses =
false;
71 private Vector3 lateUpdatePos;
72 private Quaternion lateUpdateRot;
75 private float drawTension;
84 private void OnAttachedToHand(
Hand attachedHand )
93 newPosesAppliedAction = SteamVR_Events.NewPosesAppliedAction( OnNewPosesApplied );
100 newPosesAppliedAction.enabled =
true;
107 newPosesAppliedAction.enabled =
false;
116 lateUpdatePos = transform.position;
117 lateUpdateRot = transform.rotation;
123 private void OnNewPosesApplied()
128 transform.position = lateUpdatePos;
129 transform.rotation = lateUpdateRot;
131 deferNewPoses =
false;
137 private void HandAttachedUpdate(
Hand hand )
140 transform.localPosition = Vector3.zero;
141 transform.localRotation = Quaternion.identity;
144 EvaluateHandedness();
148 deferNewPoses =
true;
150 Vector3 nockToarrowHand = ( arrowHand.arrowNockTransform.parent.position - nockRestTransform.position );
154 float lerp = Util.RemapNumberClamped( Time.time, nockLerpStartTime, ( nockLerpStartTime + lerpDuration ), 0f, 1f );
156 float pullLerp = Util.RemapNumberClamped( nockToarrowHand.magnitude, minPull, maxPull, 0f, 1f );
158 Vector3 arrowNockTransformToHeadset = ( ( Player.instance.hmdTransform.position + ( Vector3.down * 0.05f ) ) - arrowHand.arrowNockTransform.parent.position ).normalized;
159 Vector3 arrowHandPosition = ( arrowHand.arrowNockTransform.parent.position + ( ( arrowNockTransformToHeadset * drawOffset ) * pullLerp ) );
162 Vector3 pivotToString = ( arrowHandPosition - pivotTransform.position ).normalized;
163 Vector3 pivotToLowerHandle = ( handleTransform.position - pivotTransform.position ).normalized;
164 bowLeftVector = -Vector3.Cross( pivotToLowerHandle, pivotToString );
165 pivotTransform.rotation = Quaternion.Lerp( nockLerpStartRotation, Quaternion.LookRotation( pivotToString, bowLeftVector ), lerp );
168 if ( Vector3.Dot( nockToarrowHand, -nockTransform.forward ) > 0 )
170 float distanceToarrowHand = nockToarrowHand.magnitude * lerp;
172 nockTransform.localPosition =
new Vector3( 0f, 0f, Mathf.Clamp( -distanceToarrowHand, -maxPull, 0f ) );
174 nockDistanceTravelled = -nockTransform.localPosition.z;
176 arrowVelocity = Util.RemapNumber( nockDistanceTravelled, minPull, maxPull, arrowMinVelocity, arrowMaxVelocity );
178 drawTension = Util.RemapNumberClamped( nockDistanceTravelled, 0, maxPull, 0f, 1f );
180 this.bowDrawLinearMapping.value = drawTension;
182 if ( nockDistanceTravelled > minPull )
191 if ( ( nockDistanceTravelled > ( lastTickDistance + hapticDistanceThreshold ) ) || nockDistanceTravelled < ( lastTickDistance - hapticDistanceThreshold ) )
193 ushort hapticStrength = (ushort)Util.RemapNumber( nockDistanceTravelled, 0, maxPull, bowPullPulseStrengthLow, bowPullPulseStrengthHigh );
194 hand.controller.TriggerHapticPulse( hapticStrength );
195 hand.otherHand.controller.TriggerHapticPulse( hapticStrength );
197 drawSound.PlayBowTensionClicks( drawTension );
199 lastTickDistance = nockDistanceTravelled;
202 if ( nockDistanceTravelled >= maxPull )
204 if ( Time.time > nextStrainTick )
206 hand.controller.TriggerHapticPulse( 400 );
207 hand.otherHand.controller.TriggerHapticPulse( 400 );
209 drawSound.PlayBowTensionClicks( drawTension );
211 nextStrainTick = Time.time + Random.Range( minStrainTickTime, maxStrainTickTime );
217 nockTransform.localPosition =
new Vector3( 0f, 0f, 0f );
219 this.bowDrawLinearMapping.value = 0f;
224 if ( lerpBackToZeroRotation )
226 float lerp = Util.RemapNumber( Time.time, lerpStartTime, lerpStartTime + lerpDuration, 0, 1 );
228 pivotTransform.localRotation = Quaternion.Lerp( lerpStartRotation, Quaternion.identity, lerp );
232 lerpBackToZeroRotation =
false;
240 public void ArrowReleased()
243 hand.HoverUnlock( GetComponent<Interactable>() );
244 hand.otherHand.HoverUnlock( arrowHand.GetComponent<
Interactable>() );
246 if ( releaseSound != null )
251 this.StartCoroutine( this.ResetDrawAnim() );
256 private IEnumerator ResetDrawAnim()
258 float startTime = Time.time;
259 float startLerp = drawTension;
261 while ( Time.time < ( startTime + 0.02f ) )
263 float lerp = Util.RemapNumberClamped( Time.time, startTime, startTime + 0.02f, startLerp, 0f );
264 this.bowDrawLinearMapping.value = lerp;
268 this.bowDrawLinearMapping.value = 0;
275 public float GetArrowVelocity()
277 return arrowVelocity;
282 public void StartRotationLerp()
284 lerpStartTime = Time.time;
285 lerpBackToZeroRotation =
true;
286 lerpStartRotation = pivotTransform.localRotation;
288 Util.ResetTransform( nockTransform );
293 public void StartNock(
ArrowHand currentArrowHand )
295 arrowHand = currentArrowHand;
296 hand.HoverLock( GetComponent<Interactable>() );
298 nockLerpStartTime = Time.time;
299 nockLerpStartRotation = pivotTransform.rotation;
302 arrowSlideSound.Play();
310 private void EvaluateHandedness()
312 Hand.HandType handType = hand.GuessCurrentHandType();
314 if ( handType ==
Hand.HandType.Left )
317 if ( possibleHandSwitch && currentHandGuess == Handedness.Left )
319 possibleHandSwitch =
false;
323 if ( !possibleHandSwitch && currentHandGuess == Handedness.Right )
325 possibleHandSwitch =
true;
326 timeOfPossibleHandSwitch = Time.time;
330 if ( possibleHandSwitch && Time.time > ( timeOfPossibleHandSwitch + timeBeforeConfirmingHandSwitch ) )
332 currentHandGuess = Handedness.Left;
333 possibleHandSwitch =
false;
339 if ( possibleHandSwitch && currentHandGuess == Handedness.Right )
341 possibleHandSwitch =
false;
345 if ( !possibleHandSwitch && currentHandGuess == Handedness.Left )
347 possibleHandSwitch =
true;
348 timeOfPossibleHandSwitch = Time.time;
352 if ( possibleHandSwitch && Time.time > ( timeOfPossibleHandSwitch + timeBeforeConfirmingHandSwitch ) )
354 currentHandGuess = Handedness.Right;
355 possibleHandSwitch =
false;
362 private void DoHandednessCheck()
365 if ( currentHandGuess == Handedness.Left )
367 pivotTransform.localScale =
new Vector3( 1f, 1f, 1f );
371 pivotTransform.localScale =
new Vector3( 1f, -1f, 1f );
377 public void ArrowInPosition()
381 if ( nockSound != null )
389 public void ReleaseNock()
393 hand.HoverUnlock( GetComponent<Interactable>() );
394 this.StartCoroutine( this.ResetDrawAnim() );
399 private void ShutDown()
401 if ( hand != null && hand.otherHand.currentAttachedObject != null )
405 if ( hand.otherHand.currentAttachedObject.GetComponent<
ItemPackageReference>().itemPackage == arrowHandItemPackage )
407 hand.otherHand.DetachObject( hand.otherHand.currentAttachedObject );
415 private void OnHandFocusLost(
Hand hand )
417 gameObject.SetActive( false );
422 private void OnHandFocusAcquired(
Hand hand )
424 gameObject.SetActive( true );
425 OnAttachedToHand( hand );
430 private void OnDetachedFromHand(
Hand hand )
432 Destroy( gameObject );