创建射线检测,确定起点和终点
public class LineController : SingletonMono<LineController>
{
[HideInInspector] public Vector3 pointStartPos, pointEndPos;
[HideInInspector] public Vector3 lineDirection;
[HideInInspector] public float lineRealLength;
public Hand hand;
public float rayLength = 20.0f;
public LayerMask layerMask;
private IEventHandle_VR currentTarget;
public bool hasTarget
{
get { return currentTarget != null; }
}
public Action OnEnterEvent;
public Action OnExitEvent;
public Action OnClickEvent;
public Action<bool> OnActiveEvent;
[HideInInspector] public bool active;
private bool tempLineActive;
public SteamVR_Action_Boolean menuAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("Menu");
public SteamVR_Action_Boolean teleportAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("Teleport");
private IEventHandle_VR currentObj;
private IEventHandle_VR pressObj;
void Start()
{
hand = Player.instance.rightHand;
}
void Update()
{
if (teleportAction.GetStateDown(hand.handType))
{
tempLineActive = active;
SetActive(false);
}
else if (teleportAction.GetStateUp(hand.handType))
{
if (tempLineActive) SetActive(true);
}
if (menuAction.GetStateDown(hand.handType))
{
SetActive(!active);
}
if (!active) return;
pointStartPos = hand.transform.position;
lineDirection = hand.transform.forward;
Ray ray = new Ray(pointStartPos, lineDirection);
if (Physics.Raycast(ray, out RaycastHit hit, rayLength, layerMask))
{
if (hit.transform.TryGetComponent(out IEventHandle_VR uiTriggerSystem))
{
pointEndPos = hit.point;
lineRealLength = hit.distance;
onTrigger(uiTriggerSystem);
}
else
{
onTrigger(null);
pointEndPos = pointStartPos + (lineDirection * 10000.0f - pointStartPos).normalized * rayLength;
lineRealLength = rayLength;
}
}
else
{
onTrigger(null);
pointEndPos = pointStartPos + (lineDirection * 10000.0f - pointStartPos).normalized * rayLength;
lineRealLength = rayLength;
}
if (hand.grabPinchAction.GetStateDown(hand.handType))
{
if (currentObj == null) return;
pressObj = currentObj;
onClick(pressObj);
pressObj.OnHandDown(hand);
}
if (hand.grabPinchAction.GetStateUp(hand.handType))
{
if (pressObj == null) return;
pressObj.OnHandUp(hand);
pressObj = null;
}
if (hand.grabPinchAction.GetState(hand.handType))
{
currentObj?.OnHandStay(hand);
}
}
private void onTrigger(IEventHandle_VR target)
{
currentObj = target;
if (target == null)
{
if (currentTarget != null)
{
currentTarget.OnHandExit(hand);
onExit(currentTarget);
}
currentTarget = null;
}
else
{
if (currentTarget == null)
{
target.OnHandEnter(hand);
onEnter(target);
currentTarget = target;
}
else if (currentTarget != target)
{
currentTarget.OnHandExit(hand);
target.OnHandEnter(hand);
onExit(currentTarget);
onEnter(target);
currentTarget = target;
}
}
}
private void onEnter(IEventHandle_VR target)
{
OnEnterEvent?.Invoke();
}
private void onExit(IEventHandle_VR target)
{
OnExitEvent?.Invoke();
}
private void onClick(IEventHandle_VR target)
{
OnClickEvent?.Invoke();
}
public void SetActive(bool _active)
{
OnActiveEvent?.Invoke(_active);
active = _active;
if (!_active) onTrigger(null);
}
}
绘制射线
public class LineRenderer : MonoBehaviour
{
private LineController lineController;
public LineRenderer line;
[SerializeField] GameObject targetPoint;
void Start()
{
lineController = GetComponent<LineController>();
createLine();
createTargetPoint();
lineController.OnEnterEvent += onEnter;
lineController.OnExitEvent += onExit;
lineController.OnActiveEvent += onActive;
}
void Update()
{
line.SetPosition(0, lineController.pointStartPos);
line.SetPosition(1, lineController.pointEndPos);
targetPoint.SetActive(lineController.hasTarget);
if (lineController.hasTarget)
{
targetPoint.transform.position = lineController.pointEndPos;
}
}
void createLine()
{
line = Instantiate(line);
line.useWorldSpace = true;
line.startWidth = 0.0035f;
line.endWidth = 0.0035f;
}
void createTargetPoint()
{
targetPoint = Instantiate(targetPoint);
}
private void onEnter()
{
line.material.SetFloat("_CenterIntensity", 10.0f);
}
private void onExit()
{
line.materials[0].SetFloat("_CenterIntensity", 2.0f);
}
private void onActive(bool active)
{
line.enabled = active;
}
}
触发UI控件的各种状态,在手柄射线触发的时候调用
public class UIInputModule_VR : SingletonMono<UIInputModule_VR>
{
private EventSystem eventSystem;
private PointerEventData eventData;
private GameObject currentObj;
public HandTriggerType handTriggerType;
void Start()
{
eventSystem = GetComponent<EventSystem>();
eventData = new PointerEventData(eventSystem);
}
public void MouseEnter(GameObject obj)
{
currentObj = obj;
eventData.pointerEnter = obj;
ExecuteEvents.Execute(obj, eventData, ExecuteEvents.pointerEnterHandler);
}
public void MouseExit(GameObject obj)
{
currentObj = null;
ExecuteEvents.Execute(eventData.pointerEnter, eventData, ExecuteEvents.pointerExitHandler);
}
public void MouseDown(GameObject obj)
{
eventData.pointerPress = obj;
ExecuteEvents.Execute(obj, eventData, ExecuteEvents.pointerDownHandler);
if(handTriggerType == HandTriggerType.Down)
{
ExecuteEvents.Execute(obj, eventData, ExecuteEvents.pointerClickHandler);
}
}
public void MouseUp(GameObject obj)
{
ExecuteEvents.Execute(eventData.pointerPress, eventData, ExecuteEvents.pointerUpHandler);
ExecuteEvents.Execute(eventData.pointerPress, eventData, ExecuteEvents.deselectHandler);
if (currentObj == eventData.pointerPress && handTriggerType == HandTriggerType.Up)
{
ExecuteEvents.Execute(obj, eventData, ExecuteEvents.pointerClickHandler);
}
}
public enum HandTriggerType
{
Up, Down
}
}
public static class UIInputModuleExtension
{
public static void MouseEnter(this GameObject obj)
{
UIInputModule_VR.Instance.MouseEnter(obj);
}
public static void MouseExit(this GameObject obj)
{
UIInputModule_VR.Instance.MouseExit(obj);
}
public static void MouseDown(this GameObject obj)
{
UIInputModule_VR.Instance.MouseDown(obj);
}
public static void MouseUp(this GameObject obj)
{
UIInputModule_VR.Instance.MouseUp(obj);
}
}
其他一些按钮相关的代码
public class UIComponent_VR : MonoBehaviour, IEventHandle_VR
{
private CanvasRenderer canvasRenderer;
private RectTransform rectTransform;
private BoxCollider boxCollider;
public bool triggerSizeEveryFrame = false;
public Action OnHandEnterEvent;
public Action OnHandExitEvent;
public Action OnHandDownEvent;
public Action OnHandStayEvent;
public Action OnHandUpEvent;
protected virtual void Start()
{
boxCollider = GetComponent<BoxCollider>();
rectTransform = GetComponent<RectTransform>();
canvasRenderer = GetComponent<CanvasRenderer>();
boxCollider.isTrigger = true;
boxCollider.size = new Vector3(rectTransform.rect.width, rectTransform.rect.height);
}
protected virtual void Update()
{
if (triggerSizeEveryFrame)
{
boxCollider.size = new Vector3(rectTransform.rect.width, rectTransform.rect.height);
}
}
protected virtual void LateUpdate()
{
transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, -canvasRenderer.absoluteDepth);
}
public virtual void OnHandEnter(Hand hand)
{
OnHandEnterEvent?.Invoke();
}
public virtual void OnHandExit(Hand hand)
{
OnHandExitEvent?.Invoke();
}
public virtual void OnHandDown(Hand hand)
{
OnHandDownEvent?.Invoke();
}
public virtual void OnHandStay(Hand hand)
{
OnHandStayEvent?.Invoke();
}
public virtual void OnHandUp(Hand hand)
{
OnHandUpEvent?.Invoke();
}
}
public interface IEventHandle_VR
{
public void OnHandEnter(Hand hand);
public void OnHandExit(Hand hand);
public void OnHandDown(Hand hand);
public void OnHandStay(Hand hand);
public void OnHandUp(Hand hand);
}
Button代码
public class Button_VR : UIComponent_VR
{
public override void OnHandEnter(Hand hand)
{
base.OnHandEnter(hand);
hand.TriggerHapticPulse(1000);
gameObject.MouseEnter();
}
public override void OnHandExit(Hand hand)
{
base.OnHandExit(hand);
gameObject.MouseExit();
}
public override void OnHandDown(Hand hand)
{
base.OnHandDown(hand);
gameObject.MouseDown();
}
public override void OnHandUp(Hand hand)
{
base.OnHandUp(hand);
gameObject.MouseUp();
}
}