//======= Copyright (c) Valve Corporation, All rights reserved. =============== // // Purpose: Handles the spawning and returning of the ItemPackage // //============================================================================= using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using UnityEngine.Events; #if UNITY_EDITOR using UnityEditor; #endif namespace Valve.VR.InteractionSystem { //------------------------------------------------------------------------- [RequireComponent( typeof( Interactable ) )] public class ItemPackageSpawner : MonoBehaviour { public ItemPackage itemPackage { get { return _itemPackage; } set { CreatePreviewObject(); } } public ItemPackage _itemPackage; private bool useItemPackagePreview = true; private bool useFadedPreview = false; private GameObject previewObject; public bool requireGrabActionToTake = false; public bool requireReleaseActionToReturn = false; public bool showTriggerHint = false; [EnumFlags] public Hand.AttachmentFlags attachmentFlags = Hand.defaultAttachmentFlags; public bool takeBackItem = false; // if a hand enters this trigger and has the item this spawner dispenses at the top of the stack, remove it from the stack public bool acceptDifferentItems = false; private GameObject spawnedItem; private bool itemIsSpawned = false; public UnityEvent pickupEvent; public UnityEvent dropEvent; public bool justPickedUpItem = false; //------------------------------------------------- private void CreatePreviewObject() { if ( !useItemPackagePreview ) { return; } ClearPreview(); if ( useItemPackagePreview ) { if ( itemPackage == null ) { return; } if ( useFadedPreview == false ) // if we don't have a spawned item out there, use the regular preview { if ( itemPackage.previewPrefab != null ) { previewObject = Instantiate( itemPackage.previewPrefab, transform.position, Quaternion.identity ) as GameObject; previewObject.transform.parent = transform; previewObject.transform.localRotation = Quaternion.identity; } } else // there's a spawned item out there. Use the faded preview { if ( itemPackage.fadedPreviewPrefab != null ) { previewObject = Instantiate( itemPackage.fadedPreviewPrefab, transform.position, Quaternion.identity ) as GameObject; previewObject.transform.parent = transform; previewObject.transform.localRotation = Quaternion.identity; } } } } //------------------------------------------------- void Start() { VerifyItemPackage(); } //------------------------------------------------- private void VerifyItemPackage() { if ( itemPackage == null ) { ItemPackageNotValid(); } if ( itemPackage.itemPrefab == null ) { ItemPackageNotValid(); } } //------------------------------------------------- private void ItemPackageNotValid() { Debug.LogError("[SteamVR Interaction] ItemPackage assigned to " + gameObject.name + " is not valid. Destroying this game object." ); Destroy( gameObject ); } //------------------------------------------------- private void ClearPreview() { foreach ( Transform child in transform ) { if ( Time.time > 0 ) { GameObject.Destroy( child.gameObject ); } else { GameObject.DestroyImmediate( child.gameObject ); } } } //------------------------------------------------- void Update() { if ( ( itemIsSpawned == true ) && ( spawnedItem == null ) ) { itemIsSpawned = false; useFadedPreview = false; dropEvent.Invoke(); CreatePreviewObject(); } } //------------------------------------------------- private void OnHandHoverBegin( Hand hand ) { ItemPackage currentAttachedItemPackage = GetAttachedItemPackage( hand ); if ( currentAttachedItemPackage == itemPackage ) // the item at the top of the hand's stack has an associated ItemPackage { if ( takeBackItem && !requireReleaseActionToReturn ) // if we want to take back matching items and aren't waiting for a trigger press { TakeBackItem( hand ); } } if (!requireGrabActionToTake) // we don't require trigger press for pickup. Spawn and attach object. { SpawnAndAttachObject( hand, GrabTypes.Scripted ); } if (requireGrabActionToTake && showTriggerHint ) { hand.ShowGrabHint("PickUp"); } } //------------------------------------------------- private void TakeBackItem( Hand hand ) { RemoveMatchingItemsFromHandStack( itemPackage, hand ); if ( itemPackage.packageType == ItemPackage.ItemPackageType.TwoHanded ) { RemoveMatchingItemsFromHandStack( itemPackage, hand.otherHand ); } } //------------------------------------------------- private ItemPackage GetAttachedItemPackage( Hand hand ) { GameObject currentAttachedObject = hand.currentAttachedObject; if ( currentAttachedObject == null ) // verify the hand is holding something { return null; } ItemPackageReference packageReference = hand.currentAttachedObject.GetComponent(); if ( packageReference == null ) // verify the item in the hand is matchable { return null; } ItemPackage attachedItemPackage = packageReference.itemPackage; // return the ItemPackage reference we find. return attachedItemPackage; } //------------------------------------------------- private void HandHoverUpdate( Hand hand ) { if ( takeBackItem && requireReleaseActionToReturn ) { if (hand.isActive) { ItemPackage currentAttachedItemPackage = GetAttachedItemPackage( hand ); if (currentAttachedItemPackage == itemPackage && hand.IsGrabEnding(currentAttachedItemPackage.gameObject)) { TakeBackItem( hand ); return; // So that we don't pick up an ItemPackage the same frame that we return it } } } if ( requireGrabActionToTake ) { GrabTypes startingGrab = hand.GetGrabStarting(); if (startingGrab != GrabTypes.None) { SpawnAndAttachObject( hand, GrabTypes.Scripted); } } } //------------------------------------------------- private void OnHandHoverEnd( Hand hand ) { if ( !justPickedUpItem && requireGrabActionToTake && showTriggerHint ) { hand.HideGrabHint(); } justPickedUpItem = false; } //------------------------------------------------- private void RemoveMatchingItemsFromHandStack( ItemPackage package, Hand hand ) { if (hand == null) return; for ( int i = 0; i < hand.AttachedObjects.Count; i++ ) { ItemPackageReference packageReference = hand.AttachedObjects[i].attachedObject.GetComponent(); if ( packageReference != null ) { ItemPackage attachedObjectItemPackage = packageReference.itemPackage; if ( ( attachedObjectItemPackage != null ) && ( attachedObjectItemPackage == package ) ) { GameObject detachedItem = hand.AttachedObjects[i].attachedObject; hand.DetachObject( detachedItem ); } } } } //------------------------------------------------- private void RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType packageType, Hand hand ) { for ( int i = 0; i < hand.AttachedObjects.Count; i++ ) { ItemPackageReference packageReference = hand.AttachedObjects[i].attachedObject.GetComponent(); if ( packageReference != null ) { if ( packageReference.itemPackage.packageType == packageType ) { GameObject detachedItem = hand.AttachedObjects[i].attachedObject; hand.DetachObject( detachedItem ); } } } } //------------------------------------------------- private void SpawnAndAttachObject( Hand hand, GrabTypes grabType ) { if ( hand.otherHand != null ) { //If the other hand has this item package, take it back from the other hand ItemPackage otherHandItemPackage = GetAttachedItemPackage( hand.otherHand ); if ( otherHandItemPackage == itemPackage ) { TakeBackItem( hand.otherHand ); } } if ( showTriggerHint ) { hand.HideGrabHint(); } if ( itemPackage.otherHandItemPrefab != null ) { if ( hand.otherHand.hoverLocked ) { Debug.Log( "[SteamVR Interaction] Not attaching objects because other hand is hoverlocked and we can't deliver both items." ); return; } } // if we're trying to spawn a one-handed item, remove one and two-handed items from this hand and two-handed items from both hands if ( itemPackage.packageType == ItemPackage.ItemPackageType.OneHanded ) { RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.OneHanded, hand ); RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.TwoHanded, hand ); RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.TwoHanded, hand.otherHand ); } // if we're trying to spawn a two-handed item, remove one and two-handed items from both hands if ( itemPackage.packageType == ItemPackage.ItemPackageType.TwoHanded ) { RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.OneHanded, hand ); RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.OneHanded, hand.otherHand ); RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.TwoHanded, hand ); RemoveMatchingItemTypesFromHand( ItemPackage.ItemPackageType.TwoHanded, hand.otherHand ); } spawnedItem = GameObject.Instantiate( itemPackage.itemPrefab ); spawnedItem.SetActive( true ); hand.AttachObject( spawnedItem, grabType, attachmentFlags ); if ( ( itemPackage.otherHandItemPrefab != null ) && ( hand.otherHand.isActive ) ) { GameObject otherHandObjectToAttach = GameObject.Instantiate( itemPackage.otherHandItemPrefab ); otherHandObjectToAttach.SetActive( true ); hand.otherHand.AttachObject( otherHandObjectToAttach, grabType, attachmentFlags ); } itemIsSpawned = true; justPickedUpItem = true; if ( takeBackItem ) { useFadedPreview = true; pickupEvent.Invoke(); CreatePreviewObject(); } } } }