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();
}
}
}