VR手柄控制器封裝了底層接口的一個類

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);
        }
    }
}
相關文章
相關標籤/搜索