You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			308 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			308 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C#
		
	
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
 | 
						|
//
 | 
						|
// Purpose: The object attached to the player's hand that spawns and fires the
 | 
						|
//			arrow
 | 
						|
//
 | 
						|
//=============================================================================
 | 
						|
 | 
						|
using UnityEngine;
 | 
						|
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
 | 
						|
namespace Valve.VR.InteractionSystem
 | 
						|
{
 | 
						|
	//-------------------------------------------------------------------------
 | 
						|
	public class ArrowHand : MonoBehaviour
 | 
						|
	{
 | 
						|
		private Hand hand;
 | 
						|
		private Longbow bow;
 | 
						|
 | 
						|
		private GameObject currentArrow;
 | 
						|
		public GameObject arrowPrefab;
 | 
						|
 | 
						|
		public Transform arrowNockTransform;
 | 
						|
 | 
						|
		public float nockDistance = 0.1f;
 | 
						|
		public float lerpCompleteDistance = 0.08f;
 | 
						|
		public float rotationLerpThreshold = 0.15f;
 | 
						|
		public float positionLerpThreshold = 0.15f;
 | 
						|
 | 
						|
		private bool allowArrowSpawn = true;
 | 
						|
		private bool nocked;
 | 
						|
        private GrabTypes nockedWithType = GrabTypes.None;
 | 
						|
 | 
						|
		private bool inNockRange = false;
 | 
						|
		private bool arrowLerpComplete = false;
 | 
						|
 | 
						|
		public SoundPlayOneshot arrowSpawnSound;
 | 
						|
 | 
						|
		private AllowTeleportWhileAttachedToHand allowTeleport = null;
 | 
						|
 | 
						|
		public int maxArrowCount = 10;
 | 
						|
		private List<GameObject> arrowList;
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		void Awake()
 | 
						|
		{
 | 
						|
			allowTeleport = GetComponent<AllowTeleportWhileAttachedToHand>();
 | 
						|
			//allowTeleport.teleportAllowed = true;
 | 
						|
			allowTeleport.overrideHoverLock = false;
 | 
						|
 | 
						|
			arrowList = new List<GameObject>();
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private void OnAttachedToHand( Hand attachedHand )
 | 
						|
		{
 | 
						|
			hand = attachedHand;
 | 
						|
			FindBow();
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private GameObject InstantiateArrow()
 | 
						|
		{
 | 
						|
			GameObject arrow = Instantiate( arrowPrefab, arrowNockTransform.position, arrowNockTransform.rotation ) as GameObject;
 | 
						|
			arrow.name = "Bow Arrow";
 | 
						|
			arrow.transform.parent = arrowNockTransform;
 | 
						|
			Util.ResetTransform( arrow.transform );
 | 
						|
 | 
						|
			arrowList.Add( arrow );
 | 
						|
 | 
						|
			while ( arrowList.Count > maxArrowCount )
 | 
						|
			{
 | 
						|
				GameObject oldArrow = arrowList[0];
 | 
						|
				arrowList.RemoveAt( 0 );
 | 
						|
				if ( oldArrow )
 | 
						|
				{
 | 
						|
					Destroy( oldArrow );
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			return arrow;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private void HandAttachedUpdate( Hand hand )
 | 
						|
		{
 | 
						|
			if ( bow == null )
 | 
						|
			{
 | 
						|
				FindBow();
 | 
						|
			}
 | 
						|
 | 
						|
			if ( bow == null )
 | 
						|
			{
 | 
						|
				return;
 | 
						|
			}
 | 
						|
 | 
						|
			if ( allowArrowSpawn && ( currentArrow == null ) ) // If we're allowed to have an active arrow in hand but don't yet, spawn one
 | 
						|
			{
 | 
						|
				currentArrow = InstantiateArrow();
 | 
						|
				arrowSpawnSound.Play();
 | 
						|
			}
 | 
						|
 | 
						|
			float distanceToNockPosition = Vector3.Distance( transform.parent.position, bow.nockTransform.position );
 | 
						|
 | 
						|
			// If there's an arrow spawned in the hand and it's not nocked yet
 | 
						|
			if ( !nocked )
 | 
						|
			{
 | 
						|
				// If we're close enough to nock position that we want to start arrow rotation lerp, do so
 | 
						|
				if ( distanceToNockPosition < rotationLerpThreshold )
 | 
						|
				{
 | 
						|
					float lerp = Util.RemapNumber( distanceToNockPosition, rotationLerpThreshold, lerpCompleteDistance, 0, 1 );
 | 
						|
 | 
						|
					arrowNockTransform.rotation = Quaternion.Lerp( arrowNockTransform.parent.rotation, bow.nockRestTransform.rotation, lerp );
 | 
						|
				}
 | 
						|
				else // Not close enough for rotation lerp, reset rotation
 | 
						|
				{
 | 
						|
					arrowNockTransform.localRotation = Quaternion.identity;
 | 
						|
				}
 | 
						|
 | 
						|
				// If we're close enough to the nock position that we want to start arrow position lerp, do so
 | 
						|
				if ( distanceToNockPosition < positionLerpThreshold )
 | 
						|
				{
 | 
						|
					float posLerp = Util.RemapNumber( distanceToNockPosition, positionLerpThreshold, lerpCompleteDistance, 0, 1 );
 | 
						|
 | 
						|
					posLerp = Mathf.Clamp( posLerp, 0f, 1f );
 | 
						|
 | 
						|
					arrowNockTransform.position = Vector3.Lerp( arrowNockTransform.parent.position, bow.nockRestTransform.position, posLerp );
 | 
						|
				}
 | 
						|
				else // Not close enough for position lerp, reset position
 | 
						|
				{
 | 
						|
					arrowNockTransform.position = arrowNockTransform.parent.position;
 | 
						|
				}
 | 
						|
 | 
						|
 | 
						|
				// Give a haptic tick when lerp is visually complete
 | 
						|
				if ( distanceToNockPosition < lerpCompleteDistance )
 | 
						|
				{
 | 
						|
					if ( !arrowLerpComplete )
 | 
						|
					{
 | 
						|
						arrowLerpComplete = true;
 | 
						|
						hand.TriggerHapticPulse( 500 );
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					if ( arrowLerpComplete )
 | 
						|
					{
 | 
						|
						arrowLerpComplete = false;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				// Allow nocking the arrow when controller is close enough
 | 
						|
				if ( distanceToNockPosition < nockDistance )
 | 
						|
				{
 | 
						|
					if ( !inNockRange )
 | 
						|
					{
 | 
						|
						inNockRange = true;
 | 
						|
						bow.ArrowInPosition();
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					if ( inNockRange )
 | 
						|
					{
 | 
						|
						inNockRange = false;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
                GrabTypes bestGrab = hand.GetBestGrabbingType(GrabTypes.Pinch, true);
 | 
						|
 | 
						|
                // If arrow is close enough to the nock position and we're pressing the trigger, and we're not nocked yet, Nock
 | 
						|
                if ( ( distanceToNockPosition < nockDistance ) && bestGrab != GrabTypes.None && !nocked )
 | 
						|
				{
 | 
						|
					if ( currentArrow == null )
 | 
						|
					{
 | 
						|
						currentArrow = InstantiateArrow();
 | 
						|
					}
 | 
						|
 | 
						|
					nocked = true;
 | 
						|
                    nockedWithType = bestGrab;
 | 
						|
					bow.StartNock( this );
 | 
						|
					hand.HoverLock( GetComponent<Interactable>() );
 | 
						|
					allowTeleport.teleportAllowed = false;
 | 
						|
					currentArrow.transform.parent = bow.nockTransform;
 | 
						|
					Util.ResetTransform( currentArrow.transform );
 | 
						|
					Util.ResetTransform( arrowNockTransform );
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			// If arrow is nocked, and we release the trigger
 | 
						|
			if ( nocked && hand.IsGrabbingWithType(nockedWithType) == false )
 | 
						|
			{
 | 
						|
				if ( bow.pulled ) // If bow is pulled back far enough, fire arrow, otherwise reset arrow in arrowhand
 | 
						|
				{
 | 
						|
					FireArrow();
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					arrowNockTransform.rotation = currentArrow.transform.rotation;
 | 
						|
					currentArrow.transform.parent = arrowNockTransform;
 | 
						|
					Util.ResetTransform( currentArrow.transform );
 | 
						|
					nocked = false;
 | 
						|
                    nockedWithType = GrabTypes.None;
 | 
						|
					bow.ReleaseNock();
 | 
						|
					hand.HoverUnlock( GetComponent<Interactable>() );
 | 
						|
					allowTeleport.teleportAllowed = true;
 | 
						|
				}
 | 
						|
 | 
						|
				bow.StartRotationLerp(); // Arrow is releasing from the bow, tell the bow to lerp back to controller rotation
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private void OnDetachedFromHand( Hand hand )
 | 
						|
		{
 | 
						|
			Destroy( gameObject );
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private void FireArrow()
 | 
						|
		{
 | 
						|
			currentArrow.transform.parent = null;
 | 
						|
 | 
						|
			Arrow arrow = currentArrow.GetComponent<Arrow>();
 | 
						|
            arrow.StartRelease();
 | 
						|
            arrow.shaftRB.isKinematic = false;
 | 
						|
			arrow.shaftRB.useGravity = true;
 | 
						|
			arrow.shaftRB.transform.GetComponent<BoxCollider>().enabled = true;
 | 
						|
 | 
						|
			arrow.arrowHeadRB.isKinematic = false;
 | 
						|
			arrow.arrowHeadRB.useGravity = true;
 | 
						|
			arrow.arrowHeadRB.transform.GetComponent<BoxCollider>().enabled = true;
 | 
						|
 | 
						|
			arrow.arrowHeadRB.AddForce( currentArrow.transform.forward * bow.GetArrowVelocity(), ForceMode.VelocityChange );
 | 
						|
			arrow.arrowHeadRB.AddTorque( currentArrow.transform.forward * 10 );
 | 
						|
 | 
						|
			arrow.shaftRB.velocity = arrow.arrowHeadRB.velocity;
 | 
						|
			arrow.shaftRB.angularVelocity = arrow.arrowHeadRB.angularVelocity;
 | 
						|
 | 
						|
			nocked = false;
 | 
						|
            nockedWithType = GrabTypes.None;
 | 
						|
 | 
						|
			currentArrow.GetComponent<Arrow>().ArrowReleased( bow.GetArrowVelocity() );
 | 
						|
			bow.ArrowReleased();
 | 
						|
 | 
						|
			allowArrowSpawn = false;
 | 
						|
			Invoke( "EnableArrowSpawn", 0.5f );
 | 
						|
			StartCoroutine( ArrowReleaseHaptics() );
 | 
						|
 | 
						|
			currentArrow = null;
 | 
						|
			allowTeleport.teleportAllowed = true;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private void EnableArrowSpawn()
 | 
						|
		{
 | 
						|
			allowArrowSpawn = true;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private IEnumerator ArrowReleaseHaptics()
 | 
						|
		{
 | 
						|
			yield return new WaitForSeconds( 0.05f );
 | 
						|
 | 
						|
			hand.otherHand.TriggerHapticPulse( 1500 );
 | 
						|
			yield return new WaitForSeconds( 0.05f );
 | 
						|
 | 
						|
			hand.otherHand.TriggerHapticPulse( 800 );
 | 
						|
			yield return new WaitForSeconds( 0.05f );
 | 
						|
 | 
						|
			hand.otherHand.TriggerHapticPulse( 500 );
 | 
						|
			yield return new WaitForSeconds( 0.05f );
 | 
						|
 | 
						|
			hand.otherHand.TriggerHapticPulse( 300 );
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private void OnHandFocusLost( Hand hand )
 | 
						|
		{
 | 
						|
			gameObject.SetActive( false );
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private void OnHandFocusAcquired( Hand hand )
 | 
						|
		{
 | 
						|
			gameObject.SetActive( true );
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//-------------------------------------------------
 | 
						|
		private void FindBow()
 | 
						|
		{
 | 
						|
			bow = hand.otherHand.GetComponentInChildren<Longbow>();
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |