using System.Collections; using System.Collections.Generic; using UnityEngine; using Valve.VR.InteractionSystem; [RequireComponent(typeof(Collider))] public class Backpack : MonoBehaviour { private class HapticPulse { public Hand Hand; public ushort Duration; public HapticPulse(Hand hand, ushort duration = 2000) { Hand = hand; Duration = duration; } } public Hand.AttachmentFlags GrabFlags; public Hand[] Hands; public List Contents = new List(); private Collider Collider; private List PulseQueue = new List(4); private float NextHapticTime = 0; private bool[] HandReminded = new bool[] { false, false }; private void Awake() { Collider = GetComponent(); if (Hands.Length > HandReminded.Length) { Debug.LogError($"Backpack has >{HandReminded.Length} hands assigned, please update HandReminded accordingly."); } } private void Update() { for (int I = 0; I < Hands.Length; I++) { bool HandInBag = IsHandInBag(Hands[I]); if (!HandReminded[I] && HandInBag) { HandReminded[I] = true; if (PulseQueue.Count == 0) { PulseQueue.Add(new HapticPulse(Hands[I], 1000)); } } else if (HandReminded[I] && !HandInBag) { HandReminded[I] = false; if (PulseQueue.Count == 0) { PulseQueue.Add(new HapticPulse(Hands[I], 500)); } } } if (Time.time >= NextHapticTime && PulseQueue.Count > 0) { HapticPulse NextPulse = PulseQueue[0]; // Note: using the microsecond-based haptic pulses to avoid Vive wands getting stuck vibrating. // Don't know why it happens, and didn't find much info by googling. NextPulse.Hand.TriggerHapticPulse(NextPulse.Duration); NextHapticTime = Time.time + Time.deltaTime; PulseQueue.RemoveAt(0); } } private bool IsHandInBag(Hand hand) { Vector3 DeltaFromBag = hand.transform.position - Collider.ClosestPoint(hand.transform.position); return DeltaFromBag.magnitude < hand.hoverSphereRadius; } public void Grab(Hand hand) { if (IsHandInBag(hand) && Contents.Count > 0) { int Index = Contents.Count - 1; Throwable Item = Contents[Index]; Item.gameObject.SetActive(true); hand.AttachObject(Item.gameObject, hand.IsGrabbingWithType(GrabTypes.Pinch) ? GrabTypes.Pinch : GrabTypes.Grip, GrabFlags); Contents.RemoveAt(Index); PulseQueue.Clear(); PulseQueue.Add(new HapticPulse(hand, 2_000)); PulseQueue.Add(new HapticPulse(hand, 4_000)); PulseQueue.Add(new HapticPulse(hand, 8_000)); } } public void Store(Hand hand) { if (hand.currentAttachedObject != null) { Throwable Item = hand.currentAttachedObject.GetComponent(); if (IsHandInBag(hand) && Item != null) { Contents.Add(Item); hand.DetachObject(Item.gameObject); Item.gameObject.SetActive(false); PulseQueue.Clear(); PulseQueue.Add(new HapticPulse(hand, 15_000)); } } } }