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