using UnityEngine;
using UnityEngine.EventSystems;
namespace Unity.XR.XREAL.Samples
{
public class XREALLaserReticle : MonoBehaviour
{
/// Values that represent reticle states.
public enum ReticleState
{
/// An enum constant representing the hide option.
Hide,
/// An enum constant representing the normal option.
Normal,
/// An enum constant representing the hover option.
Hover,
}
/// The raycaster.
[SerializeField]
private XREALLaser m_Laser;
/// The default visual.
[SerializeField]
private GameObject m_DefaultVisual;
/// The hover visual.
[SerializeField]
private GameObject m_HoverVisual;
/// Flag to indicate whether the reticle object should be forcibly hidden
[SerializeField]
private bool m_ForceHideReticle = false;
/// The hit target.
private GameObject m_HitTarget;
/// True if is visible, false if not.
private bool m_IsVisible = true;
/// The default distance.
public float defaultDistance = 2.5f;
/// The reticle size ratio.
public float reticleSizeRatio = 0.02f;
[SerializeField]
private Camera m_MainCamera;
/// Gets the main camera.
private Camera MainCamera
{
get => m_MainCamera;
}
public bool ForceHideReticle
{
get => m_ForceHideReticle;
set => m_ForceHideReticle = value;
}
private void Awake()
{
if (m_MainCamera == null)
m_MainCamera = Camera.main;
SwitchReticleState(ReticleState.Hide);
}
void Start()
{
if (m_MainCamera == null)
{
m_MainCamera = Camera.main;
}
}
protected virtual void LateUpdate()
{
if (m_ForceHideReticle || m_Laser == null || m_Laser.RayOriginTransform == null || m_Laser.AttachTransform == null)
{
SwitchReticleState(ReticleState.Hide);
return;
}
Vector3 position = m_Laser.RayOriginTransform.position + m_Laser.AttachTransform.forward * defaultDistance;
Quaternion rotation = m_Laser.AttachTransform.rotation;
var result = m_Laser.GetCurrentRaycast(out RaycastHit hit, out RaycastResult raycastResult, out bool isUIHitClosest);
if (result)
{
SwitchReticleState(ReticleState.Hover);
if (isUIHitClosest)
{
position = raycastResult.worldPosition;
rotation = Quaternion.LookRotation(raycastResult.worldNormal, m_Laser.AttachTransform.forward);
}
else
{
position = hit.point;
rotation = Quaternion.LookRotation(hit.normal, m_Laser.AttachTransform.forward);
}
}
else
{
SwitchReticleState(ReticleState.Normal);
}
transform.position = position;
transform.rotation = rotation;
if (MainCamera)
transform.localScale = Vector3.one * reticleSizeRatio * (transform.position - MainCamera.transform.position).magnitude;
}
private void OnDisable()
{
SwitchReticleState(ReticleState.Hide);
}
/// Switch reticle state.
/// The state.
private void SwitchReticleState(ReticleState state)
{
switch (state)
{
case ReticleState.Hide:
m_DefaultVisual.SetActive(false);
m_HoverVisual.SetActive(false);
break;
case ReticleState.Normal:
m_DefaultVisual.SetActive(true);
m_HoverVisual.SetActive(false);
break;
case ReticleState.Hover:
m_DefaultVisual.SetActive(false);
m_HoverVisual.SetActive(true);
break;
default:
break;
}
}
/// Sets a visible.
/// True if is visible, false if not.
public void SetVisible(bool isVisible)
{
this.m_IsVisible = isVisible;
}
}
}