【已过时】Unity中HTC Vive手柄输入的获取

Unity中HTC Vive手柄输入的获取

已过时,仅适用于 SteamVR Plugin 1.2.x,不能用于 SteamVR Plugin 2.x 版本。

代码:

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using ButtonMask = SteamVR_Controller.ButtonMask;

namespace Spore.Special.Devices
{
    #region 按键说明

    // 每种按键都有对应的6个方法:
    // GetTouch、GetTouchDown、GetTouchUp、GetPressDown、GetPress、GetPressUp。
    // 其中System按钮用于调出SteamVR系统菜单,无法添加自定义功能,
    // ApplicationMenu和Grip按钮的Touch方法和Press方法一样,只在按下时返回true。
    // 同一个手柄上的两个Grip按钮其实是同一个按键。

    // 按键列表:
    // SteamVR_Controller.ButtonMask:
    //    System; 
    //    ApplicationMenu;
    //    Grip;
    //    Touchpad;
    //    Trigger;

    #endregion


    /// <summary>
    /// 将此脚本添加到 [CameraRig] 下的 Controller(left) 和 Controller(right) 上 。
    /// </summary>
    public class ViveController : MonoBehaviour
    {
        // 左右手标识
        private enum LRHand
        {
            Undefined = 0,
            LeftHand = 1,
            RightHand = 2,
        }

        [Serializable]
        private class DeviceDetectedEvent : UnityEvent<int> { }

        public static ViveController Left { get; private set; }
        public static ViveController Right { get; private set; }

        [Tooltip("设备检测间隔")]
        public byte deviceUpdateInterval = 3;

        [Tooltip("左手或者右手")]
        [SerializeField]
        private LRHand _leftOrRight = LRHand.Undefined;

        [Tooltip("检测到手柄后触发事件,参数1代表左手,参数1代表右手")]
        [SerializeField]
        private DeviceDetectedEvent _onControllerDetected;

        // 手柄设备
        private SteamVR_TrackedObject _trackObj;
        private SteamVR_Controller.Device _device;

        // 辅助检测Touchpad抬起
        private Vector2 _lastTouchpadAxis = Vector2.zero;
        // 辅助检测Trigger按下和抬起
        private bool _triggerPressedLastFrame = false;


        // 初始化
        private void Start()
        {
            _trackObj = gameObject.GetComponent<SteamVR_TrackedObject>();
            _device = SteamVR_Controller.Input((int)_trackObj.index);

            // 区分左右手
            if (_leftOrRight == LRHand.LeftHand)
            {
                Left = this;
                if (_device != null) _onControllerDetected.Invoke((int)LRHand.LeftHand);
            }
            else if (_leftOrRight == LRHand.RightHand)
            {
                Right = this;
                if (_device != null) _onControllerDetected.Invoke((int)LRHand.RightHand);
            }
            else
            {
                Log.Error(this, "请设置左右控制器。");
            }

            // 定时检测设备
            StartCoroutine(IEUpdateDevice(deviceUpdateInterval));
        }

        // 更新设备和状态
        private void LateUpdate()
        {
            //_device = SteamVR_Controller.Input((int)_trackObj.index);
            _triggerPressedLastFrame = GetTriggerPress();
        }

        #region 震动
        /// <summary>
        /// 震动此手柄。
        /// </summary>
        /// <param name="durationMicroSec">持续时间</param>
        public void Shake(ushort durationMicroSec = 5000)
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return;
            }

            _device.TriggerHapticPulse(durationMicroSec);
        }

        /// <summary>
        /// 震动指定的手柄。
        /// </summary>
        /// <param name="shakeLeft">是否震动左手手柄</param>
        /// <param name="shakeRight">是否震动右手手柄</param>
        /// <param name="durationMicroSec">持续时间</param>
        public void Shake(bool shakeLeft, bool shakeRight, ushort durationMicroSec)
        {
            //左手震动    
            if (shakeLeft && Left != null)
            {
                Left.Shake(durationMicroSec);

                //int leftDeviceIndex = SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Leftmost);
                //SteamVR_Controller.Input(leftDeviceIndex).TriggerHapticPulse(durationMicroSec);
            }

            //右手震动    
            if (shakeRight && Right != null)
            {
                Right.Shake(durationMicroSec);

                //int rightDeviceIndex = SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Rightmost);
                //SteamVR_Controller.Input(rightDeviceIndex).TriggerHapticPulse(durationMicroSec);
            }
        }

        #endregion

        #region ApplicationMenu

        // ApplicationMenu按钮的Touch方法和Press方法一样,只在按下时返回true。

        /// <summary>
        /// 按住ApplicationMenu按钮时持续触发。
        /// </summary>
        /// <returns></returns>
        public bool GetApplicationMenuPress()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetPress(ButtonMask.ApplicationMenu);
        }

        /// <summary>
        /// 按下ApplicationMenu按钮时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetApplicationMenuPressDown()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetPressDown(ButtonMask.ApplicationMenu);
        }

        /// <summary>
        /// 抬起ApplicationMenu按钮时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetApplicationMenuPressUp()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetPressUp(ButtonMask.ApplicationMenu);
        }

        #endregion

        #region Grip

        // Grip按钮的Touch方法和Press方法一样,只在按下时返回true。

        /// <summary>
        /// 按住Grip按钮时持续触发。
        /// </summary>
        /// <returns></returns>
        public bool GetGripPress()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetPress(ButtonMask.Grip);
        }

        /// <summary>
        /// 按下Grip按钮时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetGripPressDown()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetPressDown(ButtonMask.Grip);
        }

        /// <summary>
        /// 抬起Grip按钮时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetGripPressUp()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetPressUp(ButtonMask.Grip);
        }

        #endregion

        #region Trigger

        // Trigger的Touch触发要先于Press。
        // 触发press时必定触发touch。 

        /// <summary>
        /// 按压Trigger时持续触发。
        /// </summary>
        /// <returns></returns>
        public bool GetTriggerTouch()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetTouch(ButtonMask.Trigger);
        }

        /// <summary>
        /// 按下Trigger时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetTriggerTouchDown()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetTouchDown(ButtonMask.Trigger);
        }

        /// <summary>
        /// 松开Trigger时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetTriggerTouchUp()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetTouchUp(ButtonMask.Trigger);
        }

        /// <summary>
        /// 将Trigger按到底时持续触发。
        /// </summary>
        /// <returns></returns>
        public bool GetTriggerPress()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return GetTriggerAxis() == 1;
        }

        /// <summary>
        /// 将Trigger按到底时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetTriggerPressDown()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            if (!_triggerPressedLastFrame && GetTriggerPress())
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 将Trigger从底部抬起时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetTriggerPressUp()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            if (_triggerPressedLastFrame && !GetTriggerPress())
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 获取Trigger按压数值,值域 [0.0, 1.0] 。
        /// </summary>
        /// <returns></returns>
        public float GetTriggerAxis()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return 0;
            }

            Vector2 axis = _device.GetAxis(Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger);

            return axis.x;
        }

        #endregion

        #region Touchpad

        // Touchpad圆盘坐标系:
        // 正中:(0, 0)
        // 最左:(-1, 0)
        // 最右:(1, 0)
        // 最上:(0, 1)
        // 最下:(0, -1)

        /// <summary>
        /// 触摸或按住Touchpad时持续触发。
        /// </summary>
        /// <param name="axis">触摸点坐标</param>
        /// <returns></returns>
        public bool GetTouchpadTouch(out Vector2 axis)
        {
            axis = Vector2.zero;

            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            bool touched = _device.GetTouch(ButtonMask.Touchpad);

            if (touched)
            {
                axis = _device.GetAxis();
            }

            return touched;
        }

        /// <summary>
        /// 接触Touchpad时触发一次。
        /// </summary>
        /// <param name="axis">接触点坐标</param>
        /// <returns></returns>
        public bool GetTouchpadTouchDown(out Vector2 axis)
        {
            axis = Vector2.zero;

            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            bool down = _device.GetTouchDown(ButtonMask.Touchpad);

            if (down)
            {
                axis = _device.GetAxis();
            }

            return down;
        }

        /// <summary>
        /// 离开Touchpad时触发一次。
        /// </summary>
        /// <param name="axis">离开点坐标</param>
        /// <returns></returns>
        public bool GetTouchpadTouchUp(out Vector2 axis)
        {
            axis = Vector2.zero;

            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            Vector2 temp;
            if (GetTouchpadTouch(out temp))
            {
                _lastTouchpadAxis = temp;
            }

            bool up = _device.GetTouchUp(ButtonMask.Touchpad);

            if (up)
            {
                axis = _lastTouchpadAxis;
            }

            return up;
        }

        /// <summary>
        /// 按住Touchpad时持续触发。
        /// </summary>
        /// <param name="axis">按压点坐标</param>
        /// <returns></returns>
        public bool GetTouchpadPress(out Vector2 axis)
        {
            axis = Vector2.zero;

            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            bool pressed = _device.GetPress(ButtonMask.Touchpad);

            if (pressed)
            {
                axis = _device.GetAxis();
            }

            return pressed;
        }

        /// <summary>
        /// 按下Touchpad时触发一次。
        /// </summary>
        /// <param name="axis">按下点坐标</param>
        /// <returns></returns>
        public bool GetTouchpadPressDown(out Vector2 axis)
        {
            axis = Vector2.zero;

            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            bool down = _device.GetPressDown(ButtonMask.Touchpad);

            if (down)
            {
                axis = _device.GetAxis();
            }

            return down;
        }

        /// <summary>
        /// 抬起Touchpad时触发一次。
        /// </summary>
        /// <param name="axis">抬起点坐标</param>
        /// <returns></returns>
        public bool GetTouchpadPressUp(out Vector2 axis)
        {
            axis = Vector2.zero;

            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            Vector2 temp;
            if (GetTouchpadPress(out temp))
            {
                _lastTouchpadAxis = temp;
            }

            bool up = _device.GetPressUp(ButtonMask.Touchpad);

            if (up)
            {
                axis = _lastTouchpadAxis;
            }

            return up;
        }

        /// <summary>
        /// 触摸或按住Touchpad时持续触发。
        /// </summary>
        /// <returns></returns>
        public bool GetTouchpadTouch()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetTouch(ButtonMask.Touchpad);
        }

        /// <summary>
        /// 接触Touchpad时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetTouchpadTouchDown()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetTouchDown(ButtonMask.Touchpad);
        }

        /// <summary>
        /// 离开Touchpad时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetTouchpadTouchUp()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetTouchUp(ButtonMask.Touchpad);
        }

        /// <summary>
        /// 按住Touchpad时持续触发。
        /// </summary>
        /// <returns></returns>
        public bool GetTouchpadPress()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetPress(ButtonMask.Touchpad);
        }

        /// <summary>
        /// 按下Touchpad时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetTouchpadPressDown()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetPressDown(ButtonMask.Touchpad);
        }

        /// <summary>
        /// 抬起Touchpad时触发一次。
        /// </summary>
        /// <returns></returns>
        public bool GetTouchpadPressUp()
        {
            if (_device == null)
            {
                Log.Error(this, "未检测到手柄。");
                return false;
            }

            return _device.GetPressUp(ButtonMask.Touchpad);
        }

        #endregion

        private IEnumerator IEUpdateDevice(byte intervalSec)
        {
            WaitForSeconds wait;
            if (intervalSec == 0) wait = null;
            else wait = new WaitForSeconds(intervalSec);

            while (true)
            {
                _device = SteamVR_Controller.Input((int)_trackObj.index);
                yield return wait;
            }
        }

        private void OnDestroy()
        {
            StopAllCoroutines();
        }
    }
}
发布了76 篇原创文章 · 获赞 131 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/qq_21397217/article/details/85064004