using System; using UnityEngine.XR.Interaction.Toolkit.Interactables; namespace UnityEngine.XR.Interaction.Toolkit.Utilities { /// /// Utility methods for Interactables. /// public static class XRInteractableUtility { /// /// Struct to temporarily set within a block /// and restore the original value when disposed. /// internal struct AllowTriggerCollidersScope : IDisposable { bool m_Disposed; readonly bool m_OldValue; /// /// Initializes and returns and instance of . /// /// The value to set to. public AllowTriggerCollidersScope(bool newAllowTriggerColliders) { m_Disposed = false; m_OldValue = allowTriggerColliders; allowTriggerColliders = newAllowTriggerColliders; } /// /// Dispose the scope instance and restore the original value of . /// public void Dispose() { if (m_Disposed) return; m_Disposed = true; allowTriggerColliders = m_OldValue; } } /// /// Allows for and to utilize trigger colliders. /// Should be set before the function call and reset after. /// static bool allowTriggerColliders { get; set; } /// /// Calculates the closest Interactable's Collider to the given location (based on the Collider Transform position). /// The Collider volume and surface are not considered for calculation, use in this case. /// /// Interactable to find the closest Collider position. /// Location in world space to calculate the closest Collider position. /// If is returned, will contain the closest Collider, its position (in world space) and its distance squared to the given location. /// Returns if the closest Collider can be computed, for this the must have at least one active and enabled Collider. Otherwise, returns . /// /// Only active and enabled non-trigger colliders are used in the calculation. /// /// /// public static bool TryGetClosestCollider(IXRInteractable interactable, Vector3 position, out DistanceInfo distanceInfo) { Vector3 closestColliderPosition = default; var minColDistanceSqr = float.MaxValue; Collider closestCollider = null; var hasCollider = false; foreach (var col in interactable.colliders) { if (col == null || !col.gameObject.activeInHierarchy || !col.enabled || (col.isTrigger && !allowTriggerColliders)) continue; var colPosition = col.transform.position; var colDistanceSqr = (position - colPosition).sqrMagnitude; if (colDistanceSqr >= minColDistanceSqr) continue; hasCollider = true; minColDistanceSqr = colDistanceSqr; closestColliderPosition = colPosition; closestCollider = col; } distanceInfo = new DistanceInfo { point = closestColliderPosition, distanceSqr = minColDistanceSqr, collider = closestCollider, }; return hasCollider; } /// /// Calculates the point on the Interactable's Colliders that is closest to the given location /// (based on the Collider volume and surface). /// /// Interactable to find the closest point. /// Location in world space to calculate the closest point. /// /// If is returned, will contain the point (in world space) on the /// Collider that is closest to the given location, its distance squared, and the Collider that contains the point. If the given /// location is in the Collider, the closest point will be inside. Otherwise, the closest point will be on the /// surface of the Collider. /// /// Returns if the closest point can be computed, for this the must have at least one active and enabled Collider. Otherwise, returns . /// /// Only active and enabled non-trigger colliders are used in the calculation. /// The colliders can only be a , , , or convex . /// /// /// /// public static bool TryGetClosestPointOnCollider(IXRInteractable interactable, Vector3 position, out DistanceInfo distanceInfo) { Vector3 closestPoint = default; Collider closestPointCollider = null; var minPointDistanceSqr = float.MaxValue; var hasCollider = false; foreach (var col in interactable.colliders) { if (col == null || !col.gameObject.activeInHierarchy || !col.enabled || (col.isTrigger && !allowTriggerColliders)) continue; var colClosestPoint = col.ClosestPoint(position); var pointDistanceSqr = (position - colClosestPoint).sqrMagnitude; if (pointDistanceSqr >= minPointDistanceSqr) continue; hasCollider = true; minPointDistanceSqr = pointDistanceSqr; closestPoint = colClosestPoint; closestPointCollider = col; } distanceInfo = new DistanceInfo { point = closestPoint, distanceSqr = minPointDistanceSqr, collider = closestPointCollider, }; return hasCollider; } } }