using System; using UnityEngine; using UnityEngine.Events; using UnityEngine.XR.Interaction.Toolkit; [Serializable] public class PumpEvent : UnityEvent<float> { } [RequireComponent(typeof(SpringJoint))] public class XRTwoHandPumpInteractable : XRGrabInteractable { [SerializeField] private float pushDepth = 0.1f; [SerializeField] [Range(0, 1)] private float pumpThreshold = 0.1f; [SerializeField] private PumpEvent OnPumpUsed = null; private Vector3 startPosition; private XRPumpHold hold1 = null; private XRPumpHold hold2 = null; private XRBaseInteractor hand1 = null; private XRBaseInteractor hand2 = null; private Transform originalParent = null; private Rigidbody rb; public float Value { get; private set; } = 0f; protected override void Awake() { base.Awake(); SetupHandHolds(); trackPosition = false; startPosition = transform.localPosition; originalParent = transform.parent; rb = GetComponent<Rigidbody>(); } private void SetupHandHolds() { XRPumpHold[] handHolds = GetComponentsInChildren<XRPumpHold>(); if (handHolds.Length != 2) Debug.LogError(gameObject.name + " : Wrong number of XRHandHolds in children detected"); hold1 = handHolds[0]; hold2 = handHolds[1]; hold1.Setup(this); hold2.Setup(this); } public void SetupGrab(SelectEnterEventArgs args) { var interactor = args.interactor; if (!hand1) { hand1 = interactor; OnSelectEntering(args); } else { hand2 = interactor; trackPosition = true; } transform.parent = originalParent; } public void CancelGrab(SelectExitEventArgs args) { var interactor = args.interactor; trackPosition = false; if (!hand2) { hand1 = null; OnSelectExiting(args); } else { if (interactor == hand1) { OnSelectExiting(args); hand1 = hand2; SelectEnterEventArgs argsNew = new SelectEnterEventArgs(); args.interactor = hand2; args.interactable = this; OnSelectEntering(argsNew); } hand2 = null; } transform.parent = originalParent; } public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase) { base.ProcessInteractable(updatePhase); transform.localPosition = new Vector3(startPosition.x, Mathf.Clamp(transform.localPosition.y, startPosition.y - pushDepth, startPosition.y), startPosition.z); if (hand1 && hand2 && updatePhase == XRInteractionUpdateOrder.UpdatePhase.Late && (transform.localPosition.y < startPosition.y - pumpThreshold * pushDepth) && (transform.localPosition.y > startPosition.y - pushDepth)) { Value = Vector3.Dot(transform.InverseTransformDirection(new Vector3(0, -1, 0)), rb.velocity); //if (Value > 0.1f) Debug.Log(Value + "===" + transform.localPosition.y); // for debug if (Value > 0.1f) OnPumpUsed.Invoke(Value); } else { Value = 0f; } } #if UNITY_EDITOR private void OnValidate() { interactionLayerMask = 0; } #endif }