using UnityEngine; namespace OculusSampleFramework { [RequireComponent(typeof(Rigidbody))] public class DistanceGrabber : OVRGrabber { [SerializeField] public Color m_focusColor; [SerializeField] private float m_spherecastRadius; [SerializeField] private float m_noSnapThreshhold = 0.05f; [SerializeField] private bool m_useSpherecast; [SerializeField] public bool m_preventGrabThroughWalls; [SerializeField] private float m_objectPullVelocity = 10f; private float m_objectPullMaxRotationRate = 360f; private bool m_movingObjectToHand; [SerializeField] private float m_maxGrabDistance; [SerializeField] private int m_grabObjectsInLayer; [SerializeField] private int m_obstructionLayer; [SerializeField] private GameObject m_player; private DistanceGrabber m_otherHand; protected DistanceGrabbable m_target; protected Collider m_targetCollider; public bool UseSpherecast { get { return m_useSpherecast; } set { m_useSpherecast = value; GrabVolumeEnable(!m_useSpherecast); } } protected override void Start() { base.Start(); SphereCollider componentInChildren = m_player.GetComponentInChildren(); m_maxGrabDistance = componentInChildren.radius + 3f; if (m_parentHeldObject) { Debug.LogError("m_parentHeldObject incompatible with DistanceGrabber. Setting to false."); m_parentHeldObject = false; } DistanceGrabber[] array = Object.FindObjectsOfType(); for (int i = 0; i < array.Length; i++) { if (array[i] != this) { m_otherHand = array[i]; } } } private void Update() { Debug.DrawRay(base.transform.position, base.transform.forward, Color.red, 0.1f); DistanceGrabbable dgOut; Collider collOut; FindTarget(out dgOut, out collOut); if (dgOut != m_target) { if (m_target != null) { m_target.Targeted = m_otherHand.m_target == m_target; } if (m_target != null) { m_target.ClearColor(); } if (dgOut != null) { dgOut.SetColor(m_focusColor); } m_target = dgOut; m_targetCollider = collOut; if (m_target != null) { m_target.Targeted = true; } } } protected override void GrabBegin() { DistanceGrabbable target = m_target; Collider targetCollider = m_targetCollider; GrabVolumeEnable(false); if (!(target != null)) { return; } if (target.isGrabbed) { ((DistanceGrabber)target.grabbedBy).OffhandGrabbed(target); } m_grabbedObj = target; m_grabbedObj.GrabBegin(this, targetCollider); m_movingObjectToHand = true; m_lastPos = base.transform.position; m_lastRot = base.transform.rotation; Vector3 vector = targetCollider.ClosestPointOnBounds(m_gripTransform.position); if (!m_grabbedObj.snapPosition && !m_grabbedObj.snapOrientation && m_noSnapThreshhold > 0f && (vector - m_gripTransform.position).magnitude < m_noSnapThreshhold) { Vector3 vector2 = m_grabbedObj.transform.position - base.transform.position; m_movingObjectToHand = false; vector2 = Quaternion.Inverse(base.transform.rotation) * vector2; m_grabbedObjectPosOff = vector2; Quaternion grabbedObjectRotOff = Quaternion.Inverse(base.transform.rotation) * m_grabbedObj.transform.rotation; m_grabbedObjectRotOff = grabbedObjectRotOff; return; } m_grabbedObjectPosOff = m_gripTransform.localPosition; if ((bool)m_grabbedObj.snapOffset) { Vector3 position = m_grabbedObj.snapOffset.position; if (m_controller == OVRInput.Controller.LTouch) { position.x = 0f - position.x; } m_grabbedObjectPosOff += position; } m_grabbedObjectRotOff = m_gripTransform.localRotation; if ((bool)m_grabbedObj.snapOffset) { m_grabbedObjectRotOff = m_grabbedObj.snapOffset.rotation * m_grabbedObjectRotOff; } } protected override void MoveGrabbedObject(Vector3 pos, Quaternion rot, bool forceTeleport = false) { if (m_grabbedObj == null) { return; } Rigidbody grabbedRigidbody = m_grabbedObj.grabbedRigidbody; Vector3 vector = pos + rot * m_grabbedObjectPosOff; Quaternion quaternion = rot * m_grabbedObjectRotOff; if (m_movingObjectToHand) { float num = m_objectPullVelocity * Time.deltaTime; Vector3 vector2 = vector - m_grabbedObj.transform.position; if (num * num * 1.1f > vector2.sqrMagnitude) { m_movingObjectToHand = false; } else { vector2.Normalize(); vector = m_grabbedObj.transform.position + vector2 * num; quaternion = Quaternion.RotateTowards(m_grabbedObj.transform.rotation, quaternion, m_objectPullMaxRotationRate * Time.deltaTime); } } grabbedRigidbody.MovePosition(vector); grabbedRigidbody.MoveRotation(quaternion); } private static DistanceGrabbable HitInfoToGrabbable(RaycastHit hitInfo) { if (hitInfo.collider != null) { GameObject gameObject = hitInfo.collider.gameObject; return gameObject.GetComponent() ?? gameObject.GetComponentInParent(); } return null; } protected bool FindTarget(out DistanceGrabbable dgOut, out Collider collOut) { dgOut = null; collOut = null; float num = float.MaxValue; foreach (OVRGrabbable key in m_grabCandidates.Keys) { DistanceGrabbable distanceGrabbable = key as DistanceGrabbable; if (!(distanceGrabbable != null) || !distanceGrabbable.InRange || (distanceGrabbable.isGrabbed && !distanceGrabbable.allowOffhandGrab)) { continue; } for (int i = 0; i < distanceGrabbable.grabPoints.Length; i++) { Collider collider = distanceGrabbable.grabPoints[i]; Vector3 vector = collider.ClosestPointOnBounds(m_gripTransform.position); float sqrMagnitude = (m_gripTransform.position - vector).sqrMagnitude; if (!(sqrMagnitude < num)) { continue; } bool flag = true; if (m_preventGrabThroughWalls) { Ray ray = new Ray { direction = distanceGrabbable.transform.position - m_gripTransform.position, origin = m_gripTransform.position }; Debug.DrawRay(ray.origin, ray.direction, Color.red, 0.1f); RaycastHit hitInfo; if (Physics.Raycast(ray, out hitInfo, m_maxGrabDistance, 1 << m_obstructionLayer)) { float magnitude = (collider.ClosestPointOnBounds(m_gripTransform.position) - m_gripTransform.position).magnitude; if ((double)magnitude > (double)hitInfo.distance * 1.1) { flag = false; } } } if (flag) { num = sqrMagnitude; dgOut = distanceGrabbable; collOut = collider; } } } if (dgOut == null && m_useSpherecast) { return FindTargetWithSpherecast(out dgOut, out collOut); } return dgOut != null; } protected bool FindTargetWithSpherecast(out DistanceGrabbable dgOut, out Collider collOut) { dgOut = null; collOut = null; Ray ray = new Ray(m_gripTransform.position, m_gripTransform.forward); RaycastHit hitInfo; if (Physics.SphereCast(ray, m_spherecastRadius, out hitInfo, m_maxGrabDistance, 1 << m_grabObjectsInLayer)) { DistanceGrabbable distanceGrabbable = null; Collider collider = null; if (hitInfo.collider != null) { distanceGrabbable = hitInfo.collider.gameObject.GetComponentInParent(); collider = ((!(distanceGrabbable == null)) ? hitInfo.collider : null); if ((bool)distanceGrabbable) { dgOut = distanceGrabbable; collOut = collider; } } if (distanceGrabbable != null && m_preventGrabThroughWalls) { ray.direction = hitInfo.point - m_gripTransform.position; dgOut = distanceGrabbable; collOut = collider; RaycastHit hitInfo2; if (Physics.Raycast(ray, out hitInfo2, 1 << m_obstructionLayer)) { DistanceGrabbable distanceGrabbable2 = null; if (hitInfo.collider != null) { distanceGrabbable2 = hitInfo2.collider.gameObject.GetComponentInParent(); } if (distanceGrabbable2 != distanceGrabbable && hitInfo2.distance < hitInfo.distance) { dgOut = null; collOut = null; } } } } return dgOut != null; } protected override void GrabVolumeEnable(bool enabled) { if (m_useSpherecast) { enabled = false; } base.GrabVolumeEnable(enabled); } protected override void OffhandGrabbed(OVRGrabbable grabbable) { base.OffhandGrabbed(grabbable); } } }