创建射线检测,确定起点和终点
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 UITriggerSystem currentTarget;
private IEventHandle_VR currentTarget;
/// <summary>
/// 当前是否有触发对象
/// </summary>
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);
//Debug.DrawLine(pointStartPos, lineDirection * rayLength, Color.green);
}
else
{
onTrigger(null);
pointEndPos = pointStartPos + (lineDirection * 10000.0f - pointStartPos).normalized * rayLength;
lineRealLength = rayLength;
}
}
else
{
onTrigger(null);
//pointEndPos = lineDirection * rayLength * 1000.0f;//有较大的误差,还不知道怎么解决,希望大佬看到可以留言解决,暂时用下面的方法。
pointEndPos = pointStartPos + (lineDirection * 10000.0f - pointStartPos).normalized * rayLength;
lineRealLength = rayLength;
//Debug.DrawLine(pointStartPos, lineDirection * rayLength, Color.magenta);
}
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);
//Debug.Log($"离开{currentTarget}");
}
currentTarget = null;
}
else
{
//第一次
if (currentTarget == null)
{
target.OnHandEnter(hand);
onEnter(target);
//Debug.Log($"进入{target}");
currentTarget = target;
}
else if (currentTarget != target)//第n次
{
currentTarget.OnHandExit(hand);
target.OnHandEnter(hand);
onExit(currentTarget);
onEnter(target);
//Debug.Log($"进入{target},离开{currentTarget}");
currentTarget = target;
}
}
}
/// <summary>
/// 射线进入
/// </summary>
private void onEnter(IEventHandle_VR target)
{
//Debug.Log("进入");
OnEnterEvent?.Invoke();
}
/// <summary>
/// 射线进入
/// </summary>
private void onExit(IEventHandle_VR target)
{
//Debug.Log("离开");
OnExitEvent?.Invoke();
}
/// <summary>
/// 手柄扣动扳机
/// </summary>
private void onClick(IEventHandle_VR target)
{
//Debug.Log("手柄点击");
OnClickEvent?.Invoke();
}
/// <summary>
/// 激活或者关闭射线检测
/// </summary>
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;
}
// Update is called once per frame
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
{
/// <summary>
/// 手柄进入触发
/// </summary>
public void OnHandEnter(Hand hand);
/// <summary>
/// 手柄离开触发
/// </summary>
public void OnHandExit(Hand hand);
/// <summary>
/// 手柄按下触发
/// </summary>
public void OnHandDown(Hand hand);
/// <summary>
/// 手柄停留触发
/// </summary>
public void OnHandStay(Hand hand);
/// <summary>
/// 手柄抬起触发
/// </summary>
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();
}
}
文章来源地址https://www.toymoban.com/news/detail-514868.html
文章来源:https://www.toymoban.com/news/detail-514868.html
到了这里,关于Unity中使用VR手柄射线触发UI事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!