This script allows you to interact with a menu using VR controllers.
- Create a menu that uses Unity UI as its Source, and set its Canvas to act in World Space.
- For each Button in contains, attach a Box Collider that covers it.
- Copy/paste the script below into a C# script named TouchUI.cs, and attach it to each of the VR rig's controllers (the objects with the Tracked Pose Driver component)
- Fill in the Touch UI Inspector, optionally assigning a Line Renderer to provide a line pointing from the controller.
- For each, assign a Trigger Input Axis name, and define this name in Unity's Input Manager. Give the input a positive button of "joystick button 14" and "joystick button 15" for LeftTrigger / RightTrigger respectively.
TouchUI.cs:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class TouchUI : MonoBehaviour
{
#region Variables
[Header ("Input")]
[SerializeField] public LayerMask layerMask = new LayerMask ();
[SerializeField] private string triggerInputAxis;
[Header ("Visual")]
[SerializeField] LineRenderer lineRenderer = null;
[SerializeField] private Color lineSelectColor = Color.white;
[SerializeField] private Color lineDeselectColor = Color.grey;
[SerializeField] private float lineWidth = 0.06f;
private Vector3[] points;
private Selectable selectable;
private bool waitForTriggerRelease;
#endregion
#region UnityStandards
private void Start ()
{
points = new Vector3[2];
points[0] = Vector3.zero;
points[1] = transform.position + new Vector3 (0, 0, 20);
if (lineRenderer)
{
lineRenderer.startWidth = lineWidth;
lineRenderer.endWidth = lineWidth;
lineRenderer.SetPositions (points);
lineRenderer.enabled = true;
}
}
private void Update ()
{
AlignLineRenderer ();
DetectClicks ();
}
#endregion
#region PrivateFunctions
private void AlignLineRenderer ()
{
Ray ray = new Ray (transform.position, transform.forward);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, layerMask))
{
points[1] = transform.forward + new Vector3 (0, 0, hit.distance);
if (lineRenderer)
{
lineRenderer.startColor = lineSelectColor;
lineRenderer.endColor = lineSelectColor;
}
selectable = hit.collider.gameObject.GetComponent<Selectable> ();
if (selectable)
{
selectable.Select ();
}
}
else
{
points[1] = transform.forward + new Vector3 (0, 0, 20);
if (lineRenderer)
{
lineRenderer.startColor = lineDeselectColor;
lineRenderer.endColor = lineDeselectColor;
}
if (selectable)
{
if (EventSystem.current.currentSelectedGameObject && EventSystem.current.currentSelectedGameObject == selectable.gameObject)
{
EventSystem.current.SetSelectedGameObject (null);
}
selectable = null;
}
}
if (lineRenderer)
{
lineRenderer.SetPositions (points);
lineRenderer.material.color = lineRenderer.startColor;
}
}
private void DetectClicks ()
{
if (Input.GetAxis (triggerInputAxis) > 0f)
{
if (waitForTriggerRelease)
{
return;
}
if (selectable)
{
Button button = selectable as Button;
if (button)
{
button.onClick?.Invoke ();
}
waitForTriggerRelease = true;
}
}
else
{
waitForTriggerRelease = false;
}
}
#endregion
}