using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace BNG {
///
/// Point a line at our GazePointer
///
public class UIPointer : MonoBehaviour {
[Tooltip("The controller side this pointer is on")]
public ControllerHand ControllerSide = ControllerHand.Right;
[Tooltip("If true this object will update the VRUISystem's Left or Right Transform property")]
public bool AutoUpdateUITransforms = true;
public GameObject cursor;
private GameObject _cursor;
[Tooltip("If true the cursor and LineRenderer will be Hidden. Otherwise it will still be show at a fixed length")]
public bool HidePointerIfNoObjectsFound = true;
[Tooltip("How long the line / cursor should extend if no objects are found to point at")]
public float FixedPointerLength = 0.5f;
[Tooltip("If true the cursor object will scale based on how far away the pointer is from the origin. A cursor far away will have a larger cusor than one up close.")]
public bool CursorScaling = true;
[Tooltip("Minimum scale of the Cursor object if CursorScaling is enabled")]
public float CursorMinScale = 0.6f;
public float CursorMaxScale = 6.0f;
private Vector3 _cursorInitialLocalScale;
///
/// 0.5 = Line Goes Half Way. 1 = Line reaches end.
///
[Tooltip("Example : 0.5 = Line Goes Half Way. 1 = Line reaches end.")]
public float LineDistanceModifier = 0.8f;
///
/// Calls Events
///
VRUISystem uiSystem;
PointerEvents selectedPointerEvents;
PointerEventData data;
[Tooltip("LineRenderer to use when showing a valid UI Canvas. Leave null to attempt a GetComponent<> on this object.")]
public LineRenderer lineRenderer;
void Awake() {
if(cursor) {
_cursor = GameObject.Instantiate(cursor);
_cursor.transform.SetParent(transform);
_cursorInitialLocalScale = transform.localScale;
}
// If no Line Renderer was specified in the editor, check this Transform
if (lineRenderer == null) {
lineRenderer = GetComponent();
}
uiSystem = VRUISystem.Instance;
}
void OnEnable() {
// Automatically update VR System with our transforms
if (AutoUpdateUITransforms && ControllerSide == ControllerHand.Left) {
uiSystem.LeftPointerTransform = this.transform;
}
else if (AutoUpdateUITransforms && ControllerSide == ControllerHand.Right) {
uiSystem.RightPointerTransform = this.transform;
}
uiSystem.UpdateControllerHand(ControllerSide);
}
public void Update() {
data = uiSystem.EventData;
// Can bail early if not looking at anything
if (data == null || data.pointerCurrentRaycast.gameObject == null) {
HidePointer();
return;
}
// Set position of the cursor
if (_cursor != null ) {
bool lookingAtUI = data.pointerCurrentRaycast.module.GetType() == typeof(GraphicRaycaster);
selectedPointerEvents = data.pointerCurrentRaycast.gameObject.GetComponent();
bool lookingAtPhysicalObject = selectedPointerEvents != null;
// Are we too far away from the Physics object now?
if(lookingAtPhysicalObject) {
if (data.pointerCurrentRaycast.distance > selectedPointerEvents.MaxDistance) {
HidePointer();
return;
}
}
// Can bail immediately if not looking at a UI object or an Object with PointerEvents on it
if(!lookingAtUI && !lookingAtPhysicalObject) {
HidePointer();
return;
}
// Set as local position
float distance = Vector3.Distance(transform.position, data.pointerCurrentRaycast.worldPosition);
_cursor.transform.localPosition = new Vector3(0, 0, distance - 0.0001f);
_cursor.transform.rotation = Quaternion.FromToRotation(Vector3.forward, data.pointerCurrentRaycast.worldNormal);
// Scale cursor based on distance from main camera
float cameraDist = Vector3.Distance(Camera.main.transform.position, _cursor.transform.position);
_cursor.transform.localScale = _cursorInitialLocalScale * Mathf.Clamp(cameraDist, CursorMinScale, CursorMaxScale);
_cursor.SetActive(data.pointerCurrentRaycast.distance > 0);
}
// Update linerenderer
if (lineRenderer) {
lineRenderer.useWorldSpace = false;
lineRenderer.SetPosition(0, Vector3.zero);
lineRenderer.SetPosition(1, new Vector3(0, 0 , Vector3.Distance(transform.position, data.pointerCurrentRaycast.worldPosition) * LineDistanceModifier));
lineRenderer.enabled = data.pointerCurrentRaycast.distance > 0;
}
}
public virtual void HidePointer() {
// Hide the line and cursor
if(HidePointerIfNoObjectsFound) {
_cursor.SetActive(false);
lineRenderer.enabled = false;
}
// Show a fixed length line
else {
if (_cursor) {
_cursor.SetActive(false);
}
// Set length to fixed amount
if (lineRenderer) {
lineRenderer.useWorldSpace = false;
lineRenderer.SetPosition(0, Vector3.zero);
lineRenderer.SetPosition(1, new Vector3(0, 0, FixedPointerLength * LineDistanceModifier));
lineRenderer.enabled = true;
}
}
}
}
}