using UnityEngine.XR.Interaction.Toolkit.Locomotion.Climbing;
using UnityEngine.XR.Interaction.Toolkit.Locomotion.Teleportation;
using UnityEngine.XR.Interaction.Toolkit.Utilities;
namespace UnityEngine.XR.Interaction.Toolkit.Samples.StarterAssets
{
///
/// Affordance component used in conjunction with a to display an object
/// pointing at the target teleport destination while climbing.
///
public class ClimbTeleportDestinationIndicator : MonoBehaviour
{
[SerializeField]
[Tooltip("The interactor that drives the display and placement of the pointer object.")]
ClimbTeleportInteractor m_ClimbTeleportInteractor;
///
/// The interactor that drives the display and placement of the pointer object.
///
public ClimbTeleportInteractor climbTeleportInteractor
{
get => m_ClimbTeleportInteractor;
set => m_ClimbTeleportInteractor = value;
}
[SerializeField]
[Tooltip("The prefab to spawn when a teleport destination is chosen. The instance will spawn next to the " +
"destination and point its forward vector at the destination and its up vector at the camera.")]
GameObject m_PointerPrefab;
///
/// The prefab to spawn when a teleport destination is chosen. The instance will spawn next to the destination
/// and point its forward vector at the destination and its up vector at the camera.
///
public GameObject pointerPrefab
{
get => m_PointerPrefab;
set => m_PointerPrefab = value;
}
[SerializeField]
[Tooltip("The distance from the destination at which the pointer object spawns.")]
float m_PointerDistance = 0.3f;
///
/// The distance from the destination at which the pointer object spawns.
///
public float pointerDistance
{
get => m_PointerDistance;
set => m_PointerDistance = value;
}
TeleportationMultiAnchorVolume m_ActiveTeleportVolume;
Transform m_PointerInstance;
///
/// See .
///
protected void OnEnable()
{
if (m_ClimbTeleportInteractor == null)
{
if (!ComponentLocatorUtility.TryFindComponent(out m_ClimbTeleportInteractor))
{
Debug.LogError($"Could not find {nameof(ClimbTeleportInteractor)} in scene.");
enabled = false;
return;
}
}
m_ClimbTeleportInteractor.hoverEntered.AddListener(OnInteractorHoverEntered);
m_ClimbTeleportInteractor.hoverExited.AddListener(OnInteractorHoverExited);
}
///
/// See .
///
protected void OnDisable()
{
HideIndicator();
if (m_ActiveTeleportVolume != null)
{
m_ActiveTeleportVolume.destinationAnchorChanged -= OnClimbTeleportDestinationAnchorChanged;
m_ActiveTeleportVolume = null;
}
if (m_ClimbTeleportInteractor != null)
{
m_ClimbTeleportInteractor.hoverEntered.RemoveListener(OnInteractorHoverEntered);
m_ClimbTeleportInteractor.hoverExited.RemoveListener(OnInteractorHoverExited);
}
}
void OnInteractorHoverEntered(HoverEnterEventArgs args)
{
if (m_ActiveTeleportVolume != null || !(args.interactableObject is TeleportationMultiAnchorVolume teleportVolume))
return;
m_ActiveTeleportVolume = teleportVolume;
if (m_ActiveTeleportVolume.destinationAnchor != null)
OnClimbTeleportDestinationAnchorChanged(m_ActiveTeleportVolume);
m_ActiveTeleportVolume.destinationAnchorChanged += OnClimbTeleportDestinationAnchorChanged;
}
void OnInteractorHoverExited(HoverExitEventArgs args)
{
if (!(args.interactableObject is TeleportationMultiAnchorVolume teleportVolume) || teleportVolume != m_ActiveTeleportVolume)
return;
HideIndicator();
m_ActiveTeleportVolume.destinationAnchorChanged -= OnClimbTeleportDestinationAnchorChanged;
m_ActiveTeleportVolume = null;
}
void OnClimbTeleportDestinationAnchorChanged(TeleportationMultiAnchorVolume teleportVolume)
{
HideIndicator();
var destinationAnchor = teleportVolume.destinationAnchor;
if (destinationAnchor == null)
return;
m_PointerInstance = Instantiate(m_PointerPrefab).transform;
var cameraTrans = teleportVolume.teleportationProvider.mediator.xrOrigin.Camera.transform;
var cameraPosition = cameraTrans.position;
var destinationPosition = destinationAnchor.position;
var destinationDirectionInScreenSpace = cameraTrans.InverseTransformDirection(destinationPosition - cameraPosition);
destinationDirectionInScreenSpace.z = 0f;
var pointerDirection = cameraTrans.TransformDirection(destinationDirectionInScreenSpace).normalized;
m_PointerInstance.position = destinationPosition - pointerDirection * m_PointerDistance;
m_PointerInstance.rotation = Quaternion.LookRotation(pointerDirection, -cameraTrans.forward);
}
void HideIndicator()
{
if (m_PointerInstance != null)
Destroy(m_PointerInstance.gameObject);
}
}
}