手柄震动的代码SteamVR_Controller脚本的最上面的注释里面就有说明,其实也很简单
// Example usage: //这个栗子是左手柄震动 右手震动只需把Leftmost换成Rightmost即可 // var deviceIndex = SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Leftmost); // if (deviceIndex != -1 && SteamVR_Controller.Input(deviceIndex).GetPressDown(SteamVR_Controller.ButtonMask.Trigger)) // SteamVR_Controller.Input(deviceIndex).TriggerHapticPulse(1000); // //============================================================================= using UnityEngine; using Valve.VR; /// <summary> /// 手柄 /// </summary> public class SteamVR_Controller { //按钮 public class ButtonMask { public const ulong System = (1ul << (int)EVRButtonId.k_EButton_System); // reserved 为Steam系统保留,用来调出Steam系统菜单 public const ulong ApplicationMenu = (1ul << (int)EVRButtonId.k_EButton_ApplicationMenu); public const ulong Grip = (1ul << (int)EVRButtonId.k_EButton_Grip); public const ulong Axis0 = (1ul << (int)EVRButtonId.k_EButton_Axis0); public const ulong Axis1 = (1ul << (int)EVRButtonId.k_EButton_Axis1); public const ulong Axis2 = (1ul << (int)EVRButtonId.k_EButton_Axis2); public const ulong Axis3 = (1ul << (int)EVRButtonId.k_EButton_Axis3); public const ulong Axis4 = (1ul << (int)EVRButtonId.k_EButton_Axis4); public const ulong Touchpad = (1ul << (int)EVRButtonId.k_EButton_SteamVR_Touchpad); public const ulong Trigger = (1ul << (int)EVRButtonId.k_EButton_SteamVR_Trigger); } //设备 public class Device { public Device(uint i) { index = i; } public uint index { get; private set; } public bool valid { get; private set; } public bool connected { get { Update(); return pose.bDeviceIsConnected; } } public bool hasTracking { get { Update(); return pose.bPoseIsValid; } } public bool outOfRange { get { Update(); return pose.eTrackingResult == ETrackingResult.Running_OutOfRange || pose.eTrackingResult == ETrackingResult.Calibrating_OutOfRange; } } public bool calibrating { get { Update(); return pose.eTrackingResult == ETrackingResult.Calibrating_InProgress || pose.eTrackingResult == ETrackingResult.Calibrating_OutOfRange; } } public bool uninitialized { get { Update(); return pose.eTrackingResult == ETrackingResult.Uninitialized; } } // These values are only accurate for the last controller state change (e.g. trigger release), and by definition, will always lag behind // the predicted visual poses that drive SteamVR_TrackedObjects since they are sync‘d to the input timestamp that caused them to update. //这些值只在最近状态发生改变的才准确(例如 释放扳机),通过定义,将会总是在预测视觉动作(这个预测的信息用来驱动SteamVR_TrackedObjects)之后延迟,因为他们是和输入的时间戳同步更新的 public SteamVR_Utils.RigidTransform transform { get { Update(); return new SteamVR_Utils.RigidTransform(pose.mDeviceToAbsoluteTracking); } } public Vector3 velocity { get { Update(); return new Vector3(pose.vVelocity.v0, pose.vVelocity.v1, -pose.vVelocity.v2); } } public Vector3 angularVelocity { get { Update(); return new Vector3(-pose.vAngularVelocity.v0, -pose.vAngularVelocity.v1, pose.vAngularVelocity.v2); } } //获取状态 之前的状态 动作 public VRControllerState_t GetState() { Update(); return state; } public VRControllerState_t GetPrevState() { Update(); return prevState; } public TrackedDevicePose_t GetPose() { Update(); return pose; } VRControllerState_t state, prevState; TrackedDevicePose_t pose; int prevFrameCount = -1; public void Update() { if (Time.frameCount != prevFrameCount) { prevFrameCount = Time.frameCount; prevState = state; var system = OpenVR.System; if (system != null) { valid = system.GetControllerStateWithPose(SteamVR_Render.instance.trackingSpace, index, ref state, ref pose); UpdateHairTrigger(); } } } //长按 按下 抬起 两种参数buttonMask buttonId public bool GetPress(ulong buttonMask) { Update(); return (state.ulButtonPressed & buttonMask) != 0; } public bool GetPressDown(ulong buttonMask) { Update(); return (state.ulButtonPressed & buttonMask) != 0 && (prevState.ulButtonPressed & buttonMask) == 0; } public bool GetPressUp(ulong buttonMask) { Update(); return (state.ulButtonPressed & buttonMask) == 0 && (prevState.ulButtonPressed & buttonMask) != 0; } public bool GetPress(EVRButtonId buttonId) { return GetPress(1ul << (int)buttonId); } public bool GetPressDown(EVRButtonId buttonId) { return GetPressDown(1ul << (int)buttonId); } public bool GetPressUp(EVRButtonId buttonId) { return GetPressUp(1ul << (int)buttonId); } //触摸 按下 抬起 public bool GetTouch(ulong buttonMask) { Update(); return (state.ulButtonTouched & buttonMask) != 0; } public bool GetTouchDown(ulong buttonMask) { Update(); return (state.ulButtonTouched & buttonMask) != 0 && (prevState.ulButtonTouched & buttonMask) == 0; } public bool GetTouchUp(ulong buttonMask) { Update(); return (state.ulButtonTouched & buttonMask) == 0 && (prevState.ulButtonTouched & buttonMask) != 0; } public bool GetTouch(EVRButtonId buttonId) { return GetTouch(1ul << (int)buttonId); } public bool GetTouchDown(EVRButtonId buttonId) { return GetTouchDown(1ul << (int)buttonId); } public bool GetTouchUp(EVRButtonId buttonId) { return GetTouchUp(1ul << (int)buttonId); } //获取轴心 此处是用来返回手指在触摸板Touchpad上的位置 public Vector2 GetAxis(EVRButtonId buttonId = EVRButtonId.k_EButton_SteamVR_Touchpad) { Update(); var axisId = (uint)buttonId - (uint)EVRButtonId.k_EButton_Axis0; switch (axisId) { case 0: return new Vector2(state.rAxis0.x, state.rAxis0.y); case 1: return new Vector2(state.rAxis1.x, state.rAxis1.y); case 2: return new Vector2(state.rAxis2.x, state.rAxis2.y); case 3: return new Vector2(state.rAxis3.x, state.rAxis3.y); case 4: return new Vector2(state.rAxis4.x, state.rAxis4.y); } return Vector2.zero; } //上面提到的震动方法 public void TriggerHapticPulse(ushort durationMicroSec = 500, EVRButtonId buttonId = EVRButtonId.k_EButton_SteamVR_Touchpad) { var system = OpenVR.System; if (system != null) { var axisId = (uint)buttonId - (uint)EVRButtonId.k_EButton_Axis0; system.TriggerHapticPulse(index, axisId, (char)durationMicroSec); } } //扳机扣下或释放的量才可以改变状态 public float hairTriggerDelta = 0.1f; // amount trigger must be pulled or released to change state float hairTriggerLimit; bool hairTriggerState, hairTriggerPrevState; /// <summary> /// 更新扳机状态 /// </summary> void UpdateHairTrigger() { hairTriggerPrevState = hairTriggerState; var value = state.rAxis1.x; // trigger if (hairTriggerState) { if (value < hairTriggerLimit - hairTriggerDelta || value <= 0.0f) hairTriggerState = false; } else { if (value > hairTriggerLimit + hairTriggerDelta || value >= 1.0f) hairTriggerState = true; } hairTriggerLimit = hairTriggerState ? Mathf.Max(hairTriggerLimit, value) : Mathf.Min(hairTriggerLimit, value); } public bool GetHairTrigger() { Update(); return hairTriggerState; } public bool GetHairTriggerDown() { Update(); return hairTriggerState && !hairTriggerPrevState; } public bool GetHairTriggerUp() { Update(); return !hairTriggerState && hairTriggerPrevState; } } private static Device[] devices; /// <summary> /// 输入的具体设备 /// </summary> /// <param name="deviceIndex">Device index.</param> public static Device Input(int deviceIndex) { if (devices == null) { devices = new Device[OpenVR.k_unMaxTrackedDeviceCount]; for (uint i = 0; i < devices.Length; i++) devices[i] = new Device(i); } return devices[deviceIndex]; } public static void Update() { for (int i = 0; i < OpenVR.k_unMaxTrackedDeviceCount; i++) Input(i).Update(); } // This helper can be used in a variety of ways. Beware that indices may change // as new devices are dynamically added or removed, controllers are physically // swapped between hands, arms crossed, etc. //这个枚举帮手用很多用法.注意索引也许会因为动态的新增或者移除而改变 //或者控制器物理上的在双手/双臂之间交换,等等 public enum DeviceRelation { First, // radially Leftmost, Rightmost, // distance - also see vr.hmd.GetSortedTrackedDeviceIndicesOfClass FarthestLeft, FarthestRight, } /// <summary> /// 获取设备的索引 /// </summary> /// <returns>The device index.</returns> /// <param name="relation">Relation.</param> /// <param name="deviceClass">Device class.</param> /// <param name="relativeTo">Relative to.</param> public static int GetDeviceIndex(DeviceRelation relation, ETrackedDeviceClass deviceClass = ETrackedDeviceClass.Controller, int relativeTo = (int)OpenVR.k_unTrackedDeviceIndex_Hmd) // use -1 for absolute tracking space { var result = -1; var invXform = ((uint)relativeTo < OpenVR.k_unMaxTrackedDeviceCount) ? Input(relativeTo).transform.GetInverse() : SteamVR_Utils.RigidTransform.identity; var system = OpenVR.System; if (system == null) return result; var best = -float.MaxValue; for (int i = 0; i < OpenVR.k_unMaxTrackedDeviceCount; i++) { if (i == relativeTo || system.GetTrackedDeviceClass((uint)i) != deviceClass) continue; var device = Input(i); if (!device.connected) continue; if (relation == DeviceRelation.First) return i; float score; var pos = invXform * device.transform.pos; if (relation == DeviceRelation.FarthestRight) { score = pos.x; } else if (relation == DeviceRelation.FarthestLeft) { score = -pos.x; } else { var dir = new Vector3(pos.x, 0.0f, pos.z).normalized; var dot = Vector3.Dot(dir, Vector3.forward); var cross = Vector3.Cross(dir, Vector3.forward); if (relation == DeviceRelation.Leftmost) { score = (cross.y > 0.0f) ? 2.0f - dot : dot; } else { score = (cross.y < 0.0f) ? 2.0f - dot : dot; } } if (score > best) { result = i; best = score; } } return result; } }
另外分享一个别人的关于手柄震动的教程,比较详细~~
新建yzx_controller脚本,挂在手柄上即可
一、 手柄震动一下(真的只震动一下,也许不注意都感受不到!)
using UnityEngine; using System.Collections; public class yzx_controller : MonoBehaviour { SteamVR_TrackedObject Hand; SteamVR_Controller.Device device; // Use this for initialization void Start () { Hand = GetComponent<SteamVR_TrackedObject>(); //获得SteamVR_ TrackedObject组件 } // Update is called once per frame void Update () { if (Hand.isValid) { //防止Start函数没加载成功,保证SteamVR_ TrackedObject组件获取成功! Hand = GetComponent<SteamVR_TrackedObject>(); } //根据index,获得手柄 device = SteamVR_Controller.Input((int)Hand.index); //如果手柄的Trigger键被按下了 if (device.GetPressDown(SteamVR_Controller.ButtonMask.Trigger)) { Debug.Log("Trigger is pressed!"); //控制台输出Trigger is pressed! device.TriggerHapticPulse(500); //手柄震动函数,500代表振幅,是一个ushort类型 } }
运行程序,扣一下Trigger键,咦,好像不对劲,都没感觉发生了什么。也许你会怀疑人生,是不是都没有捕捉到Trigger键被按下的事件?
No,No,No,明明控制台打印了Trigger is pressed !
这是为什么?……
因为,手柄只震动了一下下,你根本感觉不到。当然,你也可以修改这句代码device.TriggerHapticPulse(500); 将参数500调成1000,甚至更大(数值越大,振幅越大), 然而,震感还是太低了,因为,持续时间太短了……
二、手柄持续震动(这次,真的很有震感了……)
自然想到,如果要让手柄有震感,那么震动持续的时间一定要有保证!!!
下面的代码中,你可以随便修改代码StartCoroutine(“Shock”,0.5f) 的第二个参数(代表震动持续时间),0.5f 代表手柄持续震动0.5s,想震多久就震多久……Cool !!!
我的想法:就是通过协程去执行手柄震动,然后通过Invoke函数来决定延迟时间,即控制手柄震动的持续时间。
全面修改 yzx_controller.cs脚本,代码如下:
using UnityEngine; using System.Collections; public class yzx_controller : MonoBehaviour { SteamVR_TrackedObject Hand; SteamVR_Controller.Device device; bool IsShock = false; //布尔型变量IsShock // Use this for initialization void Start () { Hand = GetComponent<SteamVR_TrackedObject>(); //获得SteamVR_ TrackedObject组件 } // Update is called once per frame void Update () { //防止Start函数没加载成功,保证SteamVR_ TrackedObject组件获取成功! if (Hand.isValid) { Hand = GetComponent<SteamVR_TrackedObject>(); } device = SteamVR_Controller.Input((int)Hand.index); //根据index,获得手柄 //如果手柄的Trigger键被按下了 if (device.GetPressDown(SteamVR_Controller.ButtonMask.Trigger)) { IsShock = false; //每次按下,IsShock为false,才能保证手柄震动 StartCoroutine("Shock",0.5f); //开启协程Shock(),第二个参数0.5f 即为协程Shock()的形参 } } //定义了一个协程 IEnumerator Shock(float durationTime) { //Invoke函数,表示durationTime秒后,执行StopShock函数; Invoke("StopShock", durationTime); //协程一直使得手柄产生震动,直到布尔型变量IsShock为false; while (!IsShock) { device.TriggerHapticPulse(500); yield return new WaitForEndOfFrame(); } } void StopShock() { IsShock = true; //关闭手柄的震动 } }
运行程序,Amazing!手柄真的真的震动起来了,而且可以随意调节震动的持续时间, So cool ……
时间: 2024-10-15 00:22:58