創(chuàng)建射線檢測,確定起點和終點
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>
/// 當前是否有觸發(fā)對象
/// </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()
{
//判斷是否觸發(fā)圓盤按鈕,如果按下就關(guān)閉射線檢測
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>
/// 激活或者關(guān)閉射線檢測
/// </summary>
public void SetActive(bool _active)
{
OnActiveEvent?.Invoke(_active);
active = _active;
if (!_active) onTrigger(null);//當手柄關(guān)閉射線檢測
}
}
繪制射線
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;
}
}
觸發(fā)UI控件的各種狀態(tài),在手柄射線觸發(fā)的時候調(diào)用
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);
}
}
其他一些按鈕相關(guān)的代碼
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>
/// 手柄進入觸發(fā)
/// </summary>
public void OnHandEnter(Hand hand);
/// <summary>
/// 手柄離開觸發(fā)
/// </summary>
public void OnHandExit(Hand hand);
/// <summary>
/// 手柄按下觸發(fā)
/// </summary>
public void OnHandDown(Hand hand);
/// <summary>
/// 手柄停留觸發(fā)
/// </summary>
public void OnHandStay(Hand hand);
/// <summary>
/// 手柄抬起觸發(fā)
/// </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();
}
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-514868.html
文章來源:http://www.zghlxwxcb.cn/news/detail-514868.html
到了這里,關(guān)于Unity中使用VR手柄射線觸發(fā)UI事件的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!