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.

379 lines
12 KiB

3 years ago
//========= Copyright 2016-2018, HTC Corporation. All rights reserved. ===========
using HTC.UnityPlugin.Utility;
using HTC.UnityPlugin.VRModuleManagement;
using System;
using UnityEngine;
namespace HTC.UnityPlugin.Vive
{
// ViveRoleProperty is a serializable class that preserve vive role using 2 strings.
// There also has a property drawer so you can use it as a serialized field in your MonoBevaviour.
// Note that when deserializing, result of type and value is based on the valid role info stored in ViveRoleEnum class
[Serializable]
public class ViveRoleProperty
{
public delegate void RoleChangedListener();
public delegate void RoleChangedListenerEx(Type previousRoleType, int previousRoleValue);
public delegate void DeviceIndexChangedListener(uint deviceIndex);
public static readonly Type DefaultRoleType = typeof(HandRole);
public static readonly int DefaultRoleValue = (int)HandRole.RightHand;
[SerializeField]
private string m_roleTypeFullName;
[SerializeField]
private string m_roleValueName;
[SerializeField]
private int m_roleValueInt;
private bool m_isTypeDirty = true;
private bool m_isValueDirty = true;
private bool m_lockUpdate;
private ViveRole.IMap m_roleMap = null;
private Type m_roleType = DefaultRoleType;
private int m_roleValue = DefaultRoleValue;
private uint m_deviceIndex = VRModule.INVALID_DEVICE_INDEX;
private Action m_onChanged;
private RoleChangedListener m_onRoleChanged;
private RoleChangedListenerEx m_onRoleChangedEx;
private DeviceIndexChangedListener m_onDeviceIndexChanged;
public Type roleType
{
get
{
Update();
return m_roleType;
}
set
{
m_isTypeDirty |= ChangeProp.Set(ref m_roleTypeFullName, value.FullName);
Update();
}
}
public int roleValue
{
get
{
Update();
return m_roleValue;
}
set
{
if (ChangeProp.Set(ref m_roleValueName, m_roleMap.RoleValueInfo.GetNameByRoleValue(value)))
{
m_roleValueInt = value;
m_isValueDirty = true;
}
Update();
}
}
[Obsolete("Use onRoleChanged instead")]
public event Action Changed
{
add { m_onChanged += value; }
remove { m_onChanged -= value; }
}
public event RoleChangedListener onRoleChanged
{
add { m_onRoleChanged += value; }
remove { m_onRoleChanged -= value; }
}
public event RoleChangedListenerEx onRoleChangedEx
{
add { m_onRoleChangedEx += value; }
remove { m_onRoleChangedEx -= value; }
}
public event DeviceIndexChangedListener onDeviceIndexChanged
{
add
{
var wasEmpty = m_onDeviceIndexChanged == null;
m_onDeviceIndexChanged += value;
if (wasEmpty && m_onDeviceIndexChanged != null && m_roleMap != null)
{
m_deviceIndex = m_roleMap.GetMappedDeviceByRoleValue(m_roleValue); // update deviceIndex before first time listening to MappingChanged event
m_roleMap.onRoleValueMappingChanged += OnMappingChanged;
}
}
remove
{
var wasEmpty = m_onDeviceIndexChanged == null;
m_onDeviceIndexChanged -= value;
if (!wasEmpty && m_onDeviceIndexChanged == null && m_roleMap != null)
{
m_roleMap.onRoleValueMappingChanged -= OnMappingChanged;
}
}
}
public static ViveRoleProperty New()
{
return New(DefaultRoleType, DefaultRoleValue);
}
public static ViveRoleProperty New(Type type, int value)
{
return New(type.FullName, ViveRoleEnum.GetInfo(type).GetNameByRoleValue(value));
}
public static ViveRoleProperty New<TRole>(TRole role)
{
return New(typeof(TRole).FullName, role.ToString());
}
public static ViveRoleProperty New(string typeFullName, string valueName)
{
var prop = new ViveRoleProperty();
prop.m_roleTypeFullName = typeFullName;
prop.m_roleValueName = valueName;
Type roleType;
if (ViveRoleEnum.ValidViveRoleTable.TryGetValue(typeFullName, out roleType))
{
var roleInfo = ViveRoleEnum.GetInfo(roleType);
var roleIndex = roleInfo.GetElementIndexByName(valueName);
if (roleIndex >= 0)
{
prop.m_roleValueInt = roleInfo.GetRoleValueByElementIndex(roleIndex);
}
else
{
prop.m_roleValueInt = roleInfo.InvalidRoleValue;
}
}
return prop;
}
public void SetTypeDirty() { m_isTypeDirty = true; }
public void SetValueDirty() { m_isValueDirty = true; }
private void OnMappingChanged(ViveRole.IMap map, ViveRole.MappingChangedEventArg args)
{
if (args.roleValue == m_roleValue)
{
m_onDeviceIndexChanged(m_deviceIndex = args.currentDeviceIndex);
}
}
// update type and value changes
public void Update()
{
if (m_lockUpdate && (m_isTypeDirty || m_isValueDirty)) { throw new Exception("Can't change value during onChange event callback"); }
var oldRoleType = m_roleType;
var oldRoleValue = m_roleValue;
var roleTypeChanged = false;
var roleValueChanged = false;
var deviceIndexChanged = false;
if (m_isTypeDirty || m_roleType == null)
{
m_isTypeDirty = false;
if (string.IsNullOrEmpty(m_roleTypeFullName) || !ViveRoleEnum.ValidViveRoleTable.TryGetValue(m_roleTypeFullName, out m_roleType))
{
m_roleType = DefaultRoleType;
}
roleTypeChanged = oldRoleType != m_roleType;
}
// maintain m_roleMap cache
// m_roleMap could be null on first update
if (roleTypeChanged || m_roleMap == null)
{
if (m_onDeviceIndexChanged != null)
{
if (m_roleMap != null)
{
m_roleMap.onRoleValueMappingChanged -= OnMappingChanged;
m_roleMap = ViveRole.GetMap(m_roleType);
m_roleMap.onRoleValueMappingChanged += OnMappingChanged;
}
else
{
m_roleMap = ViveRole.GetMap(m_roleType);
m_deviceIndex = m_roleMap.GetMappedDeviceByRoleValue(m_roleValue); // update deviceIndex before first time listening to MappingChanged event
m_roleMap.onRoleValueMappingChanged += OnMappingChanged;
}
}
else
{
m_roleMap = ViveRole.GetMap(m_roleType);
}
}
if (m_isValueDirty || roleTypeChanged)
{
m_isValueDirty = false;
var info = m_roleMap.RoleValueInfo;
if (string.IsNullOrEmpty(m_roleValueName) || !info.TryGetRoleValueByName(m_roleValueName, out m_roleValue))
{
m_roleValue = info.IsValidRoleValue(m_roleValueInt) ? m_roleValueInt : info.InvalidRoleValue;
}
roleValueChanged = oldRoleValue != m_roleValue;
}
if (roleTypeChanged || roleValueChanged)
{
if (m_onDeviceIndexChanged != null)
{
var oldDeviceIndex = m_deviceIndex;
m_deviceIndex = m_roleMap.GetMappedDeviceByRoleValue(m_roleValue);
if (VRModule.IsValidDeviceIndex(oldDeviceIndex) || VRModule.IsValidDeviceIndex(m_deviceIndex))
{
deviceIndexChanged = oldDeviceIndex != m_deviceIndex;
}
}
m_lockUpdate = true;
if (m_onChanged != null) { m_onChanged(); }
if (m_onRoleChanged != null) { m_onRoleChanged(); }
if (m_onRoleChangedEx != null) { m_onRoleChangedEx(oldRoleType, oldRoleValue); }
if (deviceIndexChanged) { m_onDeviceIndexChanged(m_deviceIndex); }
m_lockUpdate = false;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="TRole">Can be DeviceRole, HandRole or TrackerRole</typeparam>
/// <param name="role"></param>
public void SetEx<TRole>(TRole role)
{
Set(typeof(TRole).FullName, role.ToString());
}
public void Set(Type type, int value)
{
Set(type.FullName, ViveRoleEnum.GetInfo(type).GetNameByRoleValue(value));
}
public void Set(ViveRoleProperty prop)
{
Set(prop.m_roleTypeFullName, prop.m_roleValueName);
}
// set by value name to preserve the enum element, since different enum element could have same enum value
public void Set(string typeFullName, string valueName)
{
m_isTypeDirty |= ChangeProp.Set(ref m_roleTypeFullName, typeFullName);
m_isValueDirty |= ChangeProp.Set(ref m_roleValueName, valueName);
Update();
}
public uint GetDeviceIndex()
{
Update();
if (m_onDeviceIndexChanged == null)
{
return m_roleMap.GetMappedDeviceByRoleValue(m_roleValue);
}
else
{
return m_deviceIndex;
}
}
public TRole ToRole<TRole>()
{
Update();
TRole role;
var roleInfo = ViveRoleEnum.GetInfo<TRole>();
if (m_roleType != typeof(TRole) || !roleInfo.TryGetRoleByName(m_roleValueName, out role))
{
// return invalid if role type not match or the value name not found in roleInfo
return roleInfo.InvalidRole;
}
return role;
}
public bool IsRole(Type type, int value)
{
Update();
return m_roleType == type && m_roleValue == value;
}
public bool IsRole<TRole>(TRole role)
{
Update();
if (m_roleType != typeof(TRole)) { return false; }
var roleInfo = ViveRoleEnum.GetInfo<TRole>();
return m_roleValue == roleInfo.ToRoleValue(role);
}
public static bool operator ==(ViveRoleProperty p1, ViveRoleProperty p2)
{
if (ReferenceEquals(p1, p2)) { return true; }
if (ReferenceEquals(p1, null)) { return false; }
if (ReferenceEquals(p2, null)) { return false; }
if (p1.roleType != p2.roleType) { return false; }
if (p1.roleValue != p2.roleValue) { return false; }
return true;
}
public static bool operator !=(ViveRoleProperty p1, ViveRoleProperty p2)
{
return !(p1 == p2);
}
public bool Equals(ViveRoleProperty prop)
{
return this == prop;
}
public override bool Equals(object obj)
{
return Equals(obj as ViveRoleProperty);
}
public override int GetHashCode()
{
Update();
var hash = 17;
hash = hash * 23 + (m_roleType == null ? 0 : m_roleType.GetHashCode());
hash = hash * 23 + m_roleValue.GetHashCode();
return hash;
}
public override string ToString()
{
Update();
return m_roleType.Name + "." + ViveRoleEnum.GetInfo(m_roleType).GetNameByRoleValue(m_roleValue);
}
}
}