使用鼠标左键事件实现VR中的Eye Gaze Input
1.光标以及光标动画的显示
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using UnityEngine.UI; 5 6 [ExecuteInEditMode] 7 public class Pointer : MonoBehaviour 8 { 9 public Transform ArrowNormal; 10 public Image ArrowActive; 11 12 // Use this for initialization 13 void Start () 14 { 15 ArrowNormal = transform.Find("ArrowNormal"); 16 ArrowActive = transform.Find("ArrowNormal/ArrowActive").GetComponent<Image>(); 17 } 18 }
2.头盔相机射线确定光标位置以及点击逻辑的实现
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using UnityEngine.EventSystems; 5 using UnityEngine.UI; 6 7 [RequireComponent(typeof(Pointer))] 8 public class PointerCaster : MonoBehaviour 9 { 10 private GameObject currentTarget; 11 private GameObject lastActivedTarget; 12 private PointerEventData pointerEventData; 13 14 private Pointer pointer; 15 [SerializeField] 16 private float clickedDelta; 17 private float nextfocusTime; 18 19 // Use this for initialization 20 void Start () 21 { 22 // 如果没有开启XR的支持关闭些模块 23 if (!UnityEngine.XR.XRSettings.enabled) 24 gameObject.SetActive(false); 25 else 26 { 27 pointer = GetComponent<Pointer>(); 28 nextfocusTime = Time.time + clickedDelta; 29 pointerEventData = new PointerEventData(EventSystem.current); 30 } 31 } 32 33 private void SimulateInput(PointerEventData pointerData) 34 { 35 List<RaycastResult> raycastResults = new List<RaycastResult>(); 36 EventSystem.current.RaycastAll(pointerData, raycastResults); 37 if (raycastResults.Count > 0) 38 { 39 if (currentTarget == raycastResults[0].gameObject && 40 currentTarget != lastActivedTarget) 41 { 42 // 进度条的展示 43 pointer.ArrowActive.fillAmount = Mathf.Lerp(1, 0, (nextfocusTime - Time.time) / clickedDelta); 44 45 if (currentTarget.GetComponent<Selectable>()) 46 currentTarget.GetComponent<Selectable>().OnPointerEnter(pointerData); 47 48 if (Time.time >= nextfocusTime) 49 { 50 lastActivedTarget = currentTarget; 51 // 鼠标左键点击 52 if (currentTarget.GetComponent<ISubmitHandler>() != null) 53 { 54 // 点击后重置[可以进行下一次点击] 55 lastActivedTarget = null; 56 nextfocusTime = Time.time + clickedDelta; 57 currentTarget.GetComponent<ISubmitHandler>().OnSubmit(pointerData); 58 } 59 else if (currentTarget.GetComponentInParent<ISubmitHandler>() != null) 60 { 61 // 点击后重置[可以进行下一次点击] 62 lastActivedTarget = null; 63 nextfocusTime = Time.time + clickedDelta; 64 currentTarget.GetComponentInParent<ISubmitHandler>().OnSubmit(pointerData); 65 } 66 } 67 } 68 // 当前对象不是currentTarget 69 // 或者当前对象已经触发点击[currentTarget=lastActivedTarget] 70 else 71 { 72 if (currentTarget && currentTarget.GetComponent<Selectable>()) 73 currentTarget.GetComponent<Selectable>().OnPointerExit(pointerData); 74 75 if (currentTarget != raycastResults[0].gameObject) 76 { 77 currentTarget = raycastResults[0].gameObject; 78 pointer.ArrowActive.fillAmount = 0; 79 nextfocusTime = Time.time + clickedDelta; 80 } 81 } 82 } 83 // 没有目标状态重置 84 else 85 { 86 lastActivedTarget = null; 87 if (currentTarget && currentTarget.GetComponent<Selectable>()) 88 currentTarget.GetComponent<Selectable>().OnPointerExit(pointerData); 89 90 currentTarget = null; 91 pointer.ArrowActive.fillAmount = 0; 92 nextfocusTime = Time.time + clickedDelta; 93 } 94 } 95 96 // Update is called once per frame 97 void Update () 98 { 99 RaycastHit hit; 100 Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward); 101 if (Physics.Raycast(ray, out hit, 20)) 102 { 103 //pointer.ArrowNormal.position = hit.point; 104 //Debug.LogWarning(hit.point); 105 var sp = Camera.main.WorldToScreenPoint(hit.point); 106 pointerEventData.position = sp; 107 pointerEventData.button = PointerEventData.InputButton.Left; 108 // 模拟输入处理 109 SimulateInput(pointerEventData); 110 } 111 } 112 }
3.射线碰撞面的大小适应
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 [RequireComponent(typeof(BoxCollider))] 6 public class ScreenAdapter : MonoBehaviour 7 { 8 private BoxCollider bc; 9 // Use this for initialization 10 void Start () 11 { 12 bc = GetComponent<BoxCollider>(); 13 bc.size = transform.parent.GetComponent<RectTransform>().sizeDelta; 14 bc.size += new Vector3(200, 0); 15 } 16 17 // Update is called once per frame 18 void Update () { 19 20 } 21 }
4.unity3d的层次结构