效果
当头显面向UI一段时间后会实现与UI交互的效果
实例
首先制作一个UI Button,为其添加UIEnment脚本和Boxcollider组件
然后添加一个填充UI命名为HeadGaze
//为HeadGaze添加一个同名脚本实现凝视功能
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Valve.VR.InteractionSystem;
public class HeadGaze : MonoBehaviour
{
// 发送射线的位置,本实例中设置为VRCamera
public Transform headForRaycast;
// 用于标识视线的“光标”
public Transform cursor;
// 标识进度的Image组件
public Image progressImage;
// 射线发送的位移,本示例中设置y轴向上一段距离,以符合”眼部“位置
public Vector3 rayPositionOffset;
// 参与凝视交互的层,当前示例设置为UI层
public LayerMask layerMask;
// 射线长度
private float rayLength = 50f;
// 当前交互对象
private GameObject currentInteractable;
// 上一个交互对象
private GameObject lastInteractable;
// 凝视时间
public float stareTimer;
// 激活点击时限
public float activateTime = 3;
// 标识是否启用凝视交互
public bool isEnabled;
private void Awake()
{
if (cursor != null)
{
// 隐藏光标
cursor.gameObject.SetActive(false);
}
// 依情况设置,本示例中默认开启交互
isEnabled = true;
}
// Update is called once per frame
void Update()
{
// 必须要有发送射线的位置指定
if (headForRaycast == null)
return;
if (progressImage != null)
{
progressImage.fillAmount = 0;
}
if (isEnabled)
EyeRaycast();
}
private void EyeRaycast()
{
Vector3 adjustedPosition = headForRaycast.position + (headForRaycast.right * rayPositionOffset.x) +
(headForRaycast.up * rayPositionOffset.y) +
(headForRaycast.forward * rayPositionOffset.z);
Ray ray = new Ray(adjustedPosition, headForRaycast.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, rayLength, layerMask))
{
if (cursor != null)
{
cursor.gameObject.SetActive(true);
//cursor.position = hit.point;
//cursor.rotation = headForRaycast.rotation;
}
// 获取游戏对象上的Button组件
Button aButton = hit.transform.GetComponent<Button>();
if (aButton == null)
{
// 取消选择
DeactivateLastInteractable();
// 设置当前交互UI为空
currentInteractable = null;
// 返回
return;
}
currentInteractable = aButton.gameObject;
// 如果当前交互对象存在且当前交互对象不是上一次交互的对象,即找到新的交互对象
if (currentInteractable && currentInteractable != lastInteractable)
{
// 通知Button目前有悬停的事件,使之呈现悬停效果
InputModule.instance.HoverBegin(currentInteractable);
}
else if (currentInteractable == lastInteractable)
{
// 如果当前交互对象与上一个交互对象是同一个,此时认为是停留在当前交互对象上
// 凝视时间累加每一帧增加的时间
stareTimer += Time.deltaTime;
if (progressImage != null)
{
// progressImage实现逐渐填充的效果
progressImage.fillAmount = (stareTimer / activateTime);
}
// 凝视时间累加到限定的时间以上
if (stareTimer > activateTime)
{
// InputModule通知Button,此时为点击事件
InputModule.instance.Submit(currentInteractable);
// 重置凝视时间
stareTimer = 0;
// 取消选择UI
DeactivateLastInteractable();
// 凝视交互不可用
isEnabled = false;
// 1秒钟后开启凝视交互,防止出现多次点击
Invoke("ReEnable", 1f);
}
}
// 如果当前交互对象不是上一个交互对象,取消凝视交互
if (currentInteractable != lastInteractable)
DeactivateLastInteractable();
// 上一个交互对象为当前的交互对象
lastInteractable = currentInteractable;
}
else // 射线没有碰撞任何交互对象
{
DeactivateLastInteractable();
currentInteractable = null;
}
}
private void DeactivateLastInteractable()
{
// 凝视时间归零
stareTimer = 0;
// 进度图像归零
if (progressImage != null)
{
progressImage.fillAmount = 0;
}
// 上一个交互对象为空,则返回
if (lastInteractable == null)
{
return;
}
// InputModule通知上一个交互对象此时指针(射线)移出
InputModule.instance.HoverEnd(lastInteractable);
// 上一个交互对象为空
lastInteractable = null;
// 隐藏用于标识视线的“光标”
if (cursor != null)
{
cursor.gameObject.SetActive(false);
}
}
private void ReEnable()
{
isEnabled = true;
}
}
现在当我们凝视UI按钮三秒即可实现点击效果了