#if AR_FOUNDATION_PRESENT
using UnityEngine.XR.ARSubsystems;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.Interaction.Toolkit.Interactors;
using UnityEngine.XR.Interaction.Toolkit.Samples.StarterAssets;
namespace UnityEngine.XR.Interaction.Toolkit.Samples.ARStarterAssets
{
///
/// Spawns an object on physics trigger enter with an , at the point of contact on the plane.
///
[RequireComponent(typeof(Rigidbody))]
public class ARContactSpawnTrigger : MonoBehaviour
{
[SerializeField]
[Tooltip("The behavior to use to spawn objects.")]
ObjectSpawner m_ObjectSpawner;
///
/// The behavior to use to spawn objects.
///
public ObjectSpawner objectSpawner
{
get => m_ObjectSpawner;
set => m_ObjectSpawner = value;
}
[SerializeField]
[Tooltip("If enabled, spawning will be blocked if the active interactor in the associated XR Interaction Group is hovering or selecting an interactable object.")]
bool m_BlockSpawnDuringInteraction;
///
/// If enabled, spawning will be blocked if the active interactor in the associated is hovering or selecting an interactable object.
///
public bool blockSpawnDuringInteraction
{
get => m_BlockSpawnDuringInteraction;
set => m_BlockSpawnDuringInteraction = value;
}
[SerializeField]
[Tooltip("XR Interaction Group associated with this contact spawn trigger.")]
XRInteractionGroup m_InteractionGroup;
///
/// XR Interaction Group associated with this contact spawn trigger. Spawning will be blocked if an interactor from this XR Interaction Group is
/// hovering or selecting and interactable and is enabled.
///
/// If , this scripts attempts to find an component on the parent.
public XRInteractionGroup interactionGroup
{
get => m_InteractionGroup;
set => m_InteractionGroup = value;
}
[SerializeField]
[Tooltip("Whether to require that the AR Plane has an alignment of horizontal up to spawn on it.")]
bool m_RequireHorizontalUpSurface;
///
/// Whether to require that the has an alignment of to spawn on it.
///
public bool requireHorizontalUpSurface
{
get => m_RequireHorizontalUpSurface;
set => m_RequireHorizontalUpSurface = value;
}
///
/// See .
///
void Start()
{
if (m_InteractionGroup == null)
{
m_InteractionGroup = GetComponentInParent();
if (m_BlockSpawnDuringInteraction && m_InteractionGroup == null)
Debug.LogWarning("Interaction group could be found. Spawning objects will not be blocked during hover or select interaction.", this);
}
if (m_ObjectSpawner == null)
{
#if UNITY_2023_1_OR_NEWER
m_ObjectSpawner = FindAnyObjectByType();
#else
m_ObjectSpawner = FindObjectOfType();
#endif
if (m_ObjectSpawner == null)
Debug.LogWarning("Object spawner could not be found. AR Contact Spawn Trigger will be unable to spawn objects.", this);
}
}
///
/// See .
///
void OnTriggerEnter(Collider other)
{
if ((blockSpawnDuringInteraction && IsInteractionBlockingSpawn()) ||
!TryGetSpawnSurfaceData(other, out var surfacePosition, out var surfaceNormal))
return;
var infinitePlane = new Plane(surfaceNormal, surfacePosition);
var contactPoint = infinitePlane.ClosestPointOnPlane(transform.position);
m_ObjectSpawner.TrySpawnObject(contactPoint, surfaceNormal);
}
///
/// Tries to get the surface position and normal from an object to potentially spawn on.
///
/// The collider of the object to potentially spawn on.
/// The potential world position of the spawn surface.
/// The potential normal of the spawn surface.
/// Returns if is a valid spawn surface,
/// otherwise returns .
public bool TryGetSpawnSurfaceData(Collider objectCollider, out Vector3 surfacePosition, out Vector3 surfaceNormal)
{
surfacePosition = default;
surfaceNormal = default;
var arPlane = objectCollider.GetComponent();
if (arPlane == null)
return false;
if (m_RequireHorizontalUpSurface && arPlane.alignment != PlaneAlignment.HorizontalUp)
return false;
surfaceNormal = arPlane.normal;
surfacePosition = arPlane.center;
return true;
}
bool IsInteractionBlockingSpawn()
{
if (m_InteractionGroup != null && m_InteractionGroup.activeInteractor != null)
{
var hoverInteractor = (IXRHoverInteractor)m_InteractionGroup.activeInteractor;
var selectInteractor = (IXRSelectInteractor)m_InteractionGroup.activeInteractor;
var isHovering = (hoverInteractor != null) && hoverInteractor.hasHover;
var isSelecting = (selectInteractor != null) && selectInteractor.hasSelection;
return isHovering || isSelecting;
}
return false;
}
}
}
#endif