using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using VRTK; public enum TouchPadZone { Up, Down, Left, Right, None } [RequireComponent(typeof(VRTK_ControllerActions))] [RequireComponent(typeof(VRTK_ControllerEvents))] public class VRController : MonoBehaviour { public SteamVR_TrackedObject trackedObj; //控制器腳本 private SteamVR_Controller.Device device; //手柄設備 public SteamVR_Controller.Device Device { get { return device; } } public Transform handMode; //代替手柄模型的物體 public bool isCaculateLayerWeight = true; #region VRTK 腳本 public VRTK_ControllerActions actions_VRTK; public VRTK_ControllerEvents events_VRTK; public VRTK_SimplePointer simplePointer_VRTK; //射線 public VRTK_BezierPointer bezierPointer_VRTK; //貝塞爾曲線 public VRTK_UIPointer UIpointer_VRTK; //UI交互 public VRTK_BasicTeleport basicTeleport_VRTK; #endregion void OnDestroy() { //VRManager.Instance.UnRegisterController(this); } void Start() { OnInitial(); } void Update() { UpdateDevice(); CaculateLayerWeight(); } void OnInitial() { trackedObj = GetComponent<SteamVR_TrackedObject>(); actions_VRTK = GetComponent<VRTK_ControllerActions>(); events_VRTK = GetComponent<VRTK_ControllerEvents>(); //print(this.transform.IsChildOf(this.transform)); ControllerType type = VRManager.Instance.IdentifySide(this.transform); if (type == ControllerType.Left) handMode = transform.Find("shoushushou_left"); else if (type == ControllerType.Right) handMode = transform.Find("shoushushou_right"); } void UpdateDevice() { device = SteamVR_Controller.Input((int)trackedObj.index);//獲取按下的設備 } //經過trigger按下程度控制aniamtor layer層的權重 void CaculateLayerWeight() { if (isCaculateLayerWeight == false) return; if (handMode == null || handMode.GetComponent<Animator>() == null) return; Animator handAni = handMode.GetComponent<Animator>(); if (handAni.GetCurrentAnimatorStateInfo(1).IsName("EmptyInHand")) return; float weight = VRManager.Instance.GetController(VRManager.Instance.IdentifySide(this.transform)).GetTriggerAxis().x; handAni.SetLayerWeight(1, weight); } /// <summary> /// 手柄震動 /// </summary> /// <param name="strength">震動強度</param> /// <param name="duration">震動持續時間</param> /// <param name="pulseInterval">每次微小震動的間隔</param> public void TriggerHapticPulse(ushort strength, float duration, float pulseInterval) { actions_VRTK.TriggerHapticPulse(strength, duration, pulseInterval); } #region 手柄觸摸板 public Vector2 GetPadAxis() { if (device == null) return Vector2.zero; return device.GetAxis(); } //計算按下觸摸板哪塊區域 public TouchPadZone CaculateTouchPadAngle() { if (device == null) return TouchPadZone.None; float angle = 0; Vector2 touchPos = GetPadAxis(); angle = Vector2.Angle(new Vector2(0, 1), touchPos); Vector3 cross = Vector3.Cross(new Vector2(0, 1), touchPos);//叉乘算角度正負 angle = cross.z > 0 ? -angle : angle; if (angle >= -45 && angle < 45) { return TouchPadZone.Up; } else if (angle >= 45 && angle < 135) { return TouchPadZone.Right; } else if (angle >= 135 && angle <= 180 || angle >= -180 && angle <= -135) { return TouchPadZone.Down; } else if (angle < -45 && angle >= -135) { return TouchPadZone.Left; } return TouchPadZone.None; } /// <summary> /// 按住觸摸板 持續觸發 /// </summary> /// <param name="UpMethod">按住 上方向鍵的事件</param> /// <param name="DownMethod">按住 下方向鍵的事件</param> /// <param name="LeftMethod">按住 左方向鍵的事件</param> /// <param name="RightMethod">按住 右方向鍵的事件</param> public void OnTouchPadPress(UnityAction UpMethod, UnityAction DownMethod, UnityAction LeftMethod, UnityAction RightMethod) { if (device == null) return; bool isAction = device.GetPress(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; TouchPadZone zone = CaculateTouchPadAngle(); if (zone == TouchPadZone.Up) { UpMethod(); } else if (zone == TouchPadZone.Right) { RightMethod(); } else if (zone == TouchPadZone.Down) { DownMethod(); } else if (zone == TouchPadZone.Left) { LeftMethod(); } } /// <summary> /// 按下觸摸板 觸發一次 /// </summary> /// <param name="UpMethod">按下 上方向鍵的事件</param> /// <param name="DownMethod">按下 下方向鍵的事件</param> /// <param name="LeftMethod">按下 左方向鍵的事件</param> /// <param name="RightMethod">按下 右方向鍵的事件</param> public void OnTouchPadPressDown(UnityAction UpMethod, UnityAction DownMethod, UnityAction LeftMethod, UnityAction RightMethod) { if (device == null) return; bool isAction = device.GetPressDown(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; TouchPadZone zone = CaculateTouchPadAngle(); if (zone == TouchPadZone.Up) { UpMethod(); } else if (zone == TouchPadZone.Right) { RightMethod(); } else if (zone == TouchPadZone.Down) { DownMethod(); } else if (zone == TouchPadZone.Left) { LeftMethod(); } } /// <summary> /// 鬆開觸摸板 觸發一次 /// </summary> /// <param name="UpMethod">鬆開 上方向鍵的事件</param> /// <param name="DownMethod">鬆開 下方向鍵的事件</param> /// <param name="LeftMethod">鬆開 左方向鍵的事件</param> /// <param name="RightMethod">鬆開 右方向鍵的事件</param> public void OnTouchPadPressUp(UnityAction UpMethod, UnityAction DownMethod, UnityAction LeftMethod, UnityAction RightMethod) { if (device == null) return; bool isAction = device.GetPressUp(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; TouchPadZone zone = CaculateTouchPadAngle(); if (zone == TouchPadZone.Up) { UpMethod(); } else if (zone == TouchPadZone.Right) { RightMethod(); } else if (zone == TouchPadZone.Down) { DownMethod(); } else if (zone == TouchPadZone.Left) { LeftMethod(); } } /// <summary> /// 觸摸觸摸板 持續觸發 /// </summary> /// <param name="UpMethod">觸摸 上方向鍵的事件</param> /// <param name="DownMethod">觸摸 下方向鍵的事件</param> /// <param name="LeftMethod">觸摸 左方向鍵的事件</param> /// <param name="RightMethod">觸摸 右方向鍵的事件</param> public void OnTouchPadTouch(UnityAction UpMethod, UnityAction DownMethod, UnityAction LeftMethod, UnityAction RightMethod) { if (device == null) return; bool isAction = device.GetTouch(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; TouchPadZone zone = CaculateTouchPadAngle(); if (zone == TouchPadZone.Up) { UpMethod(); } else if (zone == TouchPadZone.Right) { RightMethod(); } else if (zone == TouchPadZone.Down) { DownMethod(); } else if (zone == TouchPadZone.Left) { LeftMethod(); } } /// <summary> /// 觸摸觸摸板 觸發一次 /// </summary> /// <param name="UpMethod">觸摸 上方向鍵的事件</param> /// <param name="DownMethod">觸摸 下方向鍵的事件</param> /// <param name="LeftMethod">觸摸 左方向鍵的事件</param> /// <param name="RightMethod">觸摸 右方向鍵的事件</param> public void OnTouchPadTouchDown(UnityAction UpMethod, UnityAction DownMethod, UnityAction LeftMethod, UnityAction RightMethod) { if (device == null) return; bool isAction = device.GetTouchDown(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; TouchPadZone zone = CaculateTouchPadAngle(); if (zone == TouchPadZone.Up) { UpMethod(); } else if (zone == TouchPadZone.Right) { RightMethod(); } else if (zone == TouchPadZone.Down) { DownMethod(); } else if (zone == TouchPadZone.Left) { LeftMethod(); } } //按下觸摸板 Method持續觸發 public void OnTouchPadPress(UnityAction Method) { if (device == null) return; bool isAction = device.GetPress(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; Method(); } //按下觸摸板 Method觸發一次 public void OnTouchPadPressDown(UnityAction Method) { if (device == null) return; bool isAction = device.GetPressDown(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; Method(); } //鬆開觸摸板 Method觸發一次 public void OnTouchPadPressUp(UnityAction Method) { if (device == null) return; bool isAction = device.GetPressUp(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; Method(); } //觸碰觸摸板 Method持續觸發 public void OnTouchPadTouch(UnityAction Method) { if (device == null) return; bool isAction = device.GetTouch(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; Method(); } //觸碰觸摸板 Method觸發一次 public void OnTouchPadTouchDown(UnityAction Method) { if (device == null) return; bool isAction = device.GetTouchDown(SteamVR_Controller.ButtonMask.Touchpad); if (!isAction) return; Method(); } #endregion #region 菜單按鈕 //按下菜單按鈕 public void OnMenuPressDown(UnityAction MenuMethod) { if (device == null) return; bool isAction = device.GetPressDown(SteamVR_Controller.ButtonMask.ApplicationMenu); if (!isAction) return; MenuMethod(); } //鬆開菜單按鈕 public void OnMenuPressUp(UnityAction MenuMethod) { if (device == null) return; bool isAction = device.GetPressUp(SteamVR_Controller.ButtonMask.ApplicationMenu); if (!isAction) return; MenuMethod(); } #endregion #region 扳機鍵 //按下扳機鍵 Method執行一次 public void OnTriggerPressDown(UnityAction Method) { if (device == null) return; bool isAction = device.GetPressDown(SteamVR_Controller.ButtonMask.Trigger); if (!isAction) return; Method(); } //鬆開扳機鍵 Method執行一次 public void OnTriggerPressUp(UnityAction Method) { if (device == null) return; bool isAction = device.GetPressUp(SteamVR_Controller.ButtonMask.Trigger); if (!isAction) return; Method(); } //按住扳機鍵 Method持續執行 public void OnTriggerPress(UnityAction Method) { if (device == null) return; bool isAction = device.GetPress(SteamVR_Controller.ButtonMask.Trigger); if (!isAction) return; Method(); } //輕觸扳機鍵 Method執行一次 public void OnTriggerTouchDown(UnityAction Method) { if (device == null) return; bool isAction = device.GetTouchDown(SteamVR_Controller.ButtonMask.Trigger); if (!isAction) return; Method(); } //輕觸扳機鍵 Method持續執行 public void OnTriggerTouch(UnityAction Method) { if (device == null) return; bool isAction = device.GetTouch(SteamVR_Controller.ButtonMask.Trigger); if (!isAction) return; Method(); } //輕觸扳機鍵(比Trigger Touuch Down觸發須要的力更小) Method執行一次 public void OnTriggerHairDown(UnityAction Method) { if (device == null) return; bool isAction = device.GetHairTriggerDown(); if (!isAction) return; Method(); } //獲取扳機鍵按下的程度(0.0 , 0.0) - (1.0 , 0.0) public Vector2 GetTriggerAxis() { if (device != null) return device.GetAxis(Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger); else return Vector2.zero; } #endregion #region Grip側鍵 public void OnGripPressDown(UnityAction Method) { if (device == null) return; bool isAction = device.GetPressDown(SteamVR_Controller.ButtonMask.Grip); if (!isAction) return; Method(); } #endregion }
//======= Copyright (c) Valve Corporation, All rights reserved. =============== // // Purpose: Enables/disables objects based on connectivity and assigned roles. // //============================================================================= using UnityEngine; using System.Collections.Generic; using Valve.VR; public class SteamVR_ControllerManager : MonoBehaviour { public GameObject left, right; public GameObject[] objects; // populate with objects you want to assign to additional controllers uint[] indices; // assigned bool[] connected = new bool[OpenVR.k_unMaxTrackedDeviceCount]; // controllers only // cached roles - may or may not be connected uint leftIndex = OpenVR.k_unTrackedDeviceIndexInvalid; uint rightIndex = OpenVR.k_unTrackedDeviceIndexInvalid; void Awake() { // Add left and right entries to the head of the list so we only have to operate on the list itself. var additional = (this.objects != null) ? this.objects.Length : 0; var objects = new GameObject[2 + additional]; indices = new uint[2 + additional]; objects[0] = right; indices[0] = OpenVR.k_unTrackedDeviceIndexInvalid; objects[1] = left; indices[1] = OpenVR.k_unTrackedDeviceIndexInvalid; for (int i = 0; i < additional; i++) { objects[2 + i] = this.objects[i]; indices[2 + i] = OpenVR.k_unTrackedDeviceIndexInvalid; } this.objects = objects; } void OnEnable() { for (int i = 0; i < objects.Length; i++) { var obj = objects[i]; if (obj != null) obj.SetActive(false); } OnTrackedDeviceRoleChanged(); for (int i = 0; i < SteamVR.connected.Length; i++) if (SteamVR.connected[i]) OnDeviceConnected(i, true); SteamVR_Utils.Event.Listen("input_focus", OnInputFocus); SteamVR_Utils.Event.Listen("device_connected", OnDeviceConnected); SteamVR_Utils.Event.Listen("TrackedDeviceRoleChanged", OnTrackedDeviceRoleChanged); } void OnDisable() { SteamVR_Utils.Event.Remove("input_focus", OnInputFocus); SteamVR_Utils.Event.Remove("device_connected", OnDeviceConnected); SteamVR_Utils.Event.Remove("TrackedDeviceRoleChanged", OnTrackedDeviceRoleChanged); } static string[] labels = { "left", "right" }; // Hide controllers when the dashboard is up. private void OnInputFocus(params object[] args) { bool hasFocus = (bool)args[0]; if (hasFocus) { for (int i = 0; i < objects.Length; i++) { var obj = objects[i]; if (obj != null) { var label = (i < 2) ? labels[i] : (i - 1).ToString(); ShowObject(obj.transform, "hidden (" + label + ")"); } } } else { for (int i = 0; i < objects.Length; i++) { var obj = objects[i]; if (obj != null) { var label = (i < 2) ? labels[i] : (i - 1).ToString(); HideObject(obj.transform, "hidden (" + label + ")"); } } } } // Reparents to a new object and deactivates that object (this allows // us to call SetActive in OnDeviceConnected independently. private void HideObject(Transform t, string name) { var hidden = new GameObject(name).transform; hidden.parent = t.parent; t.parent = hidden; hidden.gameObject.SetActive(false); } private void ShowObject(Transform t, string name) { var hidden = t.parent; if (hidden.gameObject.name != name) return; t.parent = hidden.parent; Destroy(hidden.gameObject); } private void SetTrackedDeviceIndex(int objectIndex, uint trackedDeviceIndex) { // First make sure no one else is already using this index. if (trackedDeviceIndex != OpenVR.k_unTrackedDeviceIndexInvalid) { for (int i = 0; i < objects.Length; i++) { if (i != objectIndex && indices[i] == trackedDeviceIndex) { var obj = objects[i]; if (obj != null) obj.SetActive(false); indices[i] = OpenVR.k_unTrackedDeviceIndexInvalid; } } } // Only set when changed. if (trackedDeviceIndex != indices[objectIndex]) { indices[objectIndex] = trackedDeviceIndex; var obj = objects[objectIndex]; if (obj != null) { if (trackedDeviceIndex == OpenVR.k_unTrackedDeviceIndexInvalid) obj.SetActive(false); else { obj.SetActive(true); obj.BroadcastMessage("SetDeviceIndex", (int)trackedDeviceIndex, SendMessageOptions.DontRequireReceiver); } } } } // Keep track of assigned roles. private void OnTrackedDeviceRoleChanged(params object[] args) { Refresh(); } // Keep track of connected controller indices. private void OnDeviceConnected(params object[] args) { var index = (uint)(int)args[0]; bool changed = this.connected[index]; this.connected[index] = false; var connected = (bool)args[1]; if (connected) { var system = OpenVR.System; if (system != null && system.GetTrackedDeviceClass(index) == ETrackedDeviceClass.Controller) { this.connected[index] = true; changed = !changed; // if we clear and set the same index, nothing has changed } } if (changed) Refresh(); } public void Refresh() { int objectIndex = 0; var system = OpenVR.System; if (system != null) { leftIndex = system.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.LeftHand); rightIndex = system.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.RightHand); } // If neither role has been assigned yet, try hooking up at least the right controller. if (leftIndex == OpenVR.k_unTrackedDeviceIndexInvalid && rightIndex == OpenVR.k_unTrackedDeviceIndexInvalid) { for (uint deviceIndex = 0; deviceIndex < connected.Length; deviceIndex++) { if (connected[deviceIndex]) { SetTrackedDeviceIndex(objectIndex++, deviceIndex); break; } } } else { SetTrackedDeviceIndex(objectIndex++, (rightIndex < connected.Length && connected[rightIndex]) ? rightIndex : OpenVR.k_unTrackedDeviceIndexInvalid); SetTrackedDeviceIndex(objectIndex++, (leftIndex < connected.Length && connected[leftIndex]) ? leftIndex : OpenVR.k_unTrackedDeviceIndexInvalid); // Assign out any additional controllers only after both left and right have been assigned. if (leftIndex != OpenVR.k_unTrackedDeviceIndexInvalid && rightIndex != OpenVR.k_unTrackedDeviceIndexInvalid) { for (uint deviceIndex = 0; deviceIndex < connected.Length; deviceIndex++) { if (objectIndex >= objects.Length) break; if (!connected[deviceIndex]) continue; if (deviceIndex != leftIndex && deviceIndex != rightIndex) { SetTrackedDeviceIndex(objectIndex++, deviceIndex); } } } } // Reset the rest. while (objectIndex < objects.Length) { SetTrackedDeviceIndex(objectIndex++, OpenVR.k_unTrackedDeviceIndexInvalid); } } }