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;
}
}
}