VR模拟枪支打靶,消灭鬼怪,换弹以及上弦等等硬核枪支操作。 使用HTCVive设备,开启SteamVR进行游玩。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
14 KiB

3 years ago
//========= Copyright 2016-2018, HTC Corporation. All rights reserved. ===========
using HTC.UnityPlugin.Utility;
using HTC.UnityPlugin.VRModuleManagement;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace HTC.UnityPlugin.Vive
{
/// <summary>
/// Defines roles for those devices that have buttons
/// </summary>
[ViveRoleEnum((int)HandRole.Invalid)]
public enum HandRole
{
Invalid = -1,
RightHand,
LeftHand,
ExternalCamera,
Controller3 = ExternalCamera,
Controller4,
Controller5,
Controller6,
Controller7,
Controller8,
Controller9,
Controller10,
Controller11,
Controller12,
Controller13,
Controller14,
Controller15,
}
public static class ConvertRoleExtension
{
[Obsolete("HandRole and DeviceRole are not related now")]
public static DeviceRole ToDeviceRole(this HandRole role)
{
switch (role)
{
case HandRole.RightHand: return DeviceRole.RightHand;
case HandRole.LeftHand: return DeviceRole.LeftHand;
case HandRole.Controller3: return DeviceRole.Controller3;
case HandRole.Controller4: return DeviceRole.Controller4;
case HandRole.Controller5: return DeviceRole.Controller5;
case HandRole.Controller6: return DeviceRole.Controller6;
case HandRole.Controller7: return DeviceRole.Controller7;
case HandRole.Controller8: return DeviceRole.Controller8;
case HandRole.Controller9: return DeviceRole.Controller9;
case HandRole.Controller10: return DeviceRole.Controller10;
case HandRole.Controller11: return DeviceRole.Controller11;
case HandRole.Controller12: return DeviceRole.Controller12;
case HandRole.Controller13: return DeviceRole.Controller13;
case HandRole.Controller14: return DeviceRole.Controller14;
case HandRole.Controller15: return DeviceRole.Controller15;
default: return (DeviceRole)((int)DeviceRole.Hmd - 1); // returns invalid value
}
}
}
public class HandRoleHandler : ViveRole.MapHandler<HandRole>
{
#if __VIU_STEAMVR
private uint[] m_sortedDevices = new uint[VRModule.MAX_DEVICE_COUNT];
#endif
private List<uint> m_sortedDeviceList = new List<uint>();
// HandRole only tracks controllers
private bool IsController(uint deviceIndex)
{
return IsController(VRModule.GetCurrentDeviceState(deviceIndex).deviceClass);
}
private bool IsController(VRModuleDeviceClass deviceClass)
{
return deviceClass == VRModuleDeviceClass.Controller;
}
private bool IsTracker(uint deviceIndex)
{
return IsTracker(VRModule.GetCurrentDeviceState(deviceIndex).deviceClass);
}
private bool IsTracker(VRModuleDeviceClass deviceClass)
{
return deviceClass == VRModuleDeviceClass.GenericTracker;
}
public override void OnAssignedAsCurrentMapHandler() { Refresh(); }
public override void OnTrackedDeviceRoleChanged() { Refresh(); }
public override void OnConnectedDeviceChanged(uint deviceIndex, VRModuleDeviceClass deviceClass, string deviceSN, bool connected)
{
if (!RoleMap.IsDeviceBound(deviceSN) && !IsController(deviceClass) && !IsTracker(deviceClass)) { return; }
Refresh();
}
public override void OnBindingChanged(string deviceSN, bool previousIsBound, HandRole previousRole, bool currentIsBound, HandRole currentRole)
{
uint deviceIndex;
if (!VRModule.TryGetConnectedDeviceIndex(deviceSN, out deviceIndex)) { return; }
Refresh();
}
public void Refresh()
{
MappingLeftRightHands();
MappingOtherControllers();
}
private void MappingLeftRightHands()
{
// assign left/right controllers according to the hint
var rightIndex = VRModule.GetRightControllerDeviceIndex();
var leftIndex = VRModule.GetLeftControllerDeviceIndex();
if (VRModule.GetCurrentDeviceState(rightIndex).isConnected)
{
MappingRoleIfUnbound(HandRole.RightHand, rightIndex);
rightIndex = RoleMap.GetMappedDeviceByRole(HandRole.RightHand);
}
else if (RoleMap.IsRoleBound(HandRole.RightHand))
{
rightIndex = RoleMap.GetMappedDeviceByRole(HandRole.RightHand);
}
else
{
rightIndex = VRModule.INVALID_DEVICE_INDEX;
}
if (VRModule.GetCurrentDeviceState(leftIndex).isConnected && leftIndex != rightIndex)
{
MappingRoleIfUnbound(HandRole.LeftHand, leftIndex);
leftIndex = RoleMap.GetMappedDeviceByRole(HandRole.LeftHand);
}
else if (RoleMap.IsRoleBound(HandRole.LeftHand))
{
leftIndex = RoleMap.GetMappedDeviceByRole(HandRole.LeftHand);
}
else
{
leftIndex = VRModule.INVALID_DEVICE_INDEX;
}
// if not both left/right controllers are assigned, find and assign them with left/right most controller
if (!VRModule.IsValidDeviceIndex(rightIndex) || !VRModule.IsValidDeviceIndex(leftIndex))
{
// find right to left sorted controllers
// FIXME: GetSortedTrackedDeviceIndicesOfClass doesn't return correct devices count right after device connected
#if __VIU_STEAMVR
if (VRModule.activeModule == SupportedVRModule.SteamVR)
{
var count = 0;
var system = Valve.VR.OpenVR.System;
if (system != null)
{
count = (int)system.GetSortedTrackedDeviceIndicesOfClass(Valve.VR.ETrackedDeviceClass.Controller, m_sortedDevices, Valve.VR.OpenVR.k_unTrackedDeviceIndex_Hmd);
}
foreach (var deviceIndex in m_sortedDevices)
{
if (m_sortedDeviceList.Count >= count) { break; }
if (IsController(deviceIndex) && deviceIndex != rightIndex && deviceIndex != leftIndex && !RoleMap.IsDeviceConnectedAndBound(deviceIndex))
{
m_sortedDeviceList.Add(deviceIndex);
}
}
}
else
#endif
{
for (uint deviceIndex = 1u; deviceIndex < VRModule.MAX_DEVICE_COUNT; ++deviceIndex)
{
if (IsController(deviceIndex) && deviceIndex != rightIndex && deviceIndex != leftIndex && !RoleMap.IsDeviceConnectedAndBound(deviceIndex))
{
m_sortedDeviceList.Add(deviceIndex);
}
}
if (m_sortedDeviceList.Count > 1)
{
SortDeviceIndicesByDirection(m_sortedDeviceList, VRModule.GetCurrentDeviceState(VRModule.HMD_DEVICE_INDEX).pose);
}
}
if (m_sortedDeviceList.Count > 0 && !VRModule.IsValidDeviceIndex(rightIndex))
{
rightIndex = m_sortedDeviceList[0];
m_sortedDeviceList.RemoveAt(0);
// mapping right most controller
MappingRole(HandRole.RightHand, rightIndex);
}
if (m_sortedDeviceList.Count > 0 && !VRModule.IsValidDeviceIndex(leftIndex))
{
leftIndex = m_sortedDeviceList[m_sortedDeviceList.Count - 1];
// mapping left most controller
MappingRole(HandRole.LeftHand, leftIndex);
}
m_sortedDeviceList.Clear();
}
if (!VRModule.IsValidDeviceIndex(rightIndex)) { UnmappingRole(HandRole.RightHand); }
if (!VRModule.IsValidDeviceIndex(leftIndex)) { UnmappingRole(HandRole.LeftHand); }
}
private void MappingOtherControllers()
{
// mapping other controllers in order of device index
var deviceIndex = 0u;
var firstFoundTracker = VRModule.INVALID_DEVICE_INDEX;
var rightIndex = RoleMap.GetMappedDeviceByRole(HandRole.RightHand);
var leftIndex = RoleMap.GetMappedDeviceByRole(HandRole.LeftHand);
for (var role = RoleInfo.MinValidRole; role <= RoleInfo.MaxValidRole; ++role)
{
if (!RoleInfo.IsValidRole(role)) { continue; }
if (role == HandRole.RightHand || role == HandRole.LeftHand) { continue; }
if (RoleMap.IsRoleBound(role)) { continue; }
// find next valid device
if (VRModule.IsValidDeviceIndex(deviceIndex))
{
while (!IsController(deviceIndex) || RoleMap.IsDeviceConnectedAndBound(deviceIndex) || deviceIndex == rightIndex || deviceIndex == leftIndex)
{
if (!VRModule.IsValidDeviceIndex(firstFoundTracker) && IsTracker(deviceIndex)) { firstFoundTracker = deviceIndex; }
if (!VRModule.IsValidDeviceIndex(++deviceIndex)) { break; }
}
}
if (VRModule.IsValidDeviceIndex(deviceIndex))
{
MappingRole(role, deviceIndex++);
}
else
{
UnmappingRole(role);
}
}
// if external camera is not mapped, try mapping first found tracker
if (!RoleMap.IsRoleMapped(HandRole.ExternalCamera) && VRModule.IsValidDeviceIndex(firstFoundTracker) && !RoleMap.IsDeviceConnectedAndBound(firstFoundTracker))
{
MappingRole(HandRole.ExternalCamera, firstFoundTracker);
}
}
private static readonly float[] s_deviceDirPoint = new float[VRModule.MAX_DEVICE_COUNT];
public static void SortDeviceIndicesByDirection(List<uint> deviceList, RigidPose sortingReference)
{
if (deviceList == null || deviceList.Count == 0) { return; }
for (int i = 0, imax = deviceList.Count; i < imax; ++i)
{
var deviceIndex = deviceList[i];
if (!VRModule.IsValidDeviceIndex(deviceIndex)) { continue; }
var deviceState = VRModule.GetCurrentDeviceState(deviceIndex);
if (deviceState.isConnected)
{
var localPos = sortingReference.InverseTransformPoint(deviceState.pose.pos);
s_deviceDirPoint[deviceIndex] = GetDirectionPoint(new Vector2(localPos.x, localPos.z));
}
else
{
s_deviceDirPoint[deviceIndex] = -1f;
}
}
deviceList.Sort(CompareDirection);
}
[Obsolete]
public static void SortDeviceIndicesByDirection(List<uint> deviceList, PoseTracker.Pose sortingReference)
{
SortDeviceIndicesByDirection(deviceList, sortingReference);
}
private static int CompareDirection(uint d1, uint d2)
{
var d1Point = s_deviceDirPoint[d1];
var d2Point = s_deviceDirPoint[d2];
var d1Valid = VRModule.IsValidDeviceIndex(d1) && d1Point >= 0f;
var d2Valid = VRModule.IsValidDeviceIndex(d2) && d2Point >= 0f;
if (!d1Valid || !d2Valid)
{
if (d1Valid) { return -1; }
if (d2Valid) { return 1; }
if (d1 < d2) { return -1; }
if (d1 > d2) { return 1; }
return 0;
}
if (d1Point < d2Point) { return -1; }
if (d1Point > d2Point) { return 1; }
return 0;
}
// Y+
// ||
// \\ 4 || 3 //
// \\ || //
// 5 \\ ^^ // 2
// =========[]========= X+
// 6 // || \\ 1
// // || \\
// // 7 || 0 \\
// ||
// less point => right side
public static float GetDirectionPoint(Vector2 pos)
{
var ax = Mathf.Abs(pos.x);
var ay = Mathf.Abs(pos.y);
if (pos.x > 0f)
{
if (pos.y < 0f)
{
if (ax < ay)
{
return 0f + (ax / ay);
}
else
{
return 1f + (1f - ay / ax);
}
}
else
{
if (ax > ay)
{
return 2f + (ay / ax);
}
else
{
return 3f + (1f - ax / ay);
}
}
}
else
{
if (pos.y > 0f)
{
if (ax < ay)
{
return 4f + (ax / ay);
}
else
{
return 5f + (1f - ay / ax);
}
}
else
{
if (ax > ay)
{
return 6f + (ay / ax);
}
else
{
return 7f + (1 - ax / ay);
}
}
}
}
}
}