using System;
namespace UnityEngine.XR.Hands.Gestures
{
///
/// A set of targets for the values of a single
/// .
///
[Serializable]
public class XRFingerShapeCondition
{
///
/// A configuration for a and its
/// desired value in a condition.
///
[Serializable]
public struct Target
{
[SerializeField]
[Tooltip("The finger shape type that is being checked in this condition.")]
XRFingerShapeType m_ShapeType;
///
/// The that is being checked in
/// this condition.
///
public XRFingerShapeType shapeType
{
get => m_ShapeType;
set => m_ShapeType = value;
}
///
/// The desired value to compare the specified
/// to in this condition.
///
public float desired
{
get => m_Desired;
set => m_Desired = Mathf.Clamp01(value);
}
[SerializeField]
[Range(0f, 1f)]
[Tooltip("The maximum the value can differ from the Desired value for the condition to be met.")]
float m_UpperTolerance;
///
/// The maximum the value can differ from the
/// for the condition to be met.
///
public float upperTolerance
{
get => m_UpperTolerance;
set => m_UpperTolerance = Mathf.Clamp01(value);
}
[Range(0f, 1f)]
[SerializeField]
[Tooltip("The minimum the value can differ from the Desired value for the condition to be met.")]
float m_LowerTolerance;
///
/// The minimum the value can differ from the
/// for the condition to be met.
///
public float lowerTolerance
{
get => m_LowerTolerance;
set => m_LowerTolerance = Mathf.Clamp01(value);
}
[HideInInspector, SerializeField, Obsolete("Deprecated. Use upperTolerance and lowerTolerance instead.")]
float m_Tolerance;
///
/// The deprecated maximum the value can differ from the
/// for the condition to be met.
///
[Obsolete("Deprecated. Use upperTolerance and lowerTolerance instead.")]
public float tolerance
{
get => m_Tolerance;
set
{
Debug.LogWarning("Deprecated. Use upperTolerance and lowerTolerance instead. Both of those properties will be set via the deprecated tolerance value.");
m_Tolerance = Mathf.Clamp01(value);
upperTolerance = m_Tolerance;
lowerTolerance = m_Tolerance;
// Reset tolerance value to zero in order to prevent further deprecated upgrade functionality
m_Tolerance = 0f;
}
}
[Range(0f, 1f)]
[SerializeField]
[Tooltip("The desired value for the finger shape.")]
float m_Desired;
}
[SerializeField]
[Tooltip("The finger to check for this condition.")]
XRHandFingerID m_FingerID = XRHandFingerID.Index;
[SerializeField]
[Tooltip("The targets to check for this condition.")]
Target[] m_Targets;
///
/// Finger shape targets to check for this finger. Setting this value
/// will update the needed for this
/// condition.
///
public Target[] targets
{
get => m_Targets;
set
{
m_Targets = value;
m_TypesNeededDirty = true;
}
}
///
/// The finger ID that this condition applies to.
///
public XRHandFingerID fingerID
{
get => m_FingerID;
set => m_FingerID = value;
}
XRFingerShapeTypes m_TypesNeeded;
bool m_TypesNeededDirty = true;
///
/// Checks if the matches the targets in
/// this condition.
///
///
/// The target values are checked in the order listed.
/// The method will return as soon as it finds
/// one value that is different from the target by more than the tolerance.
///
///
/// The hand joint updated event argument that contains the latest hand data.
///
///
/// Returns if all the finger shape conditions
/// are met. Otherwise, returns .
///
public bool CheckCondition(XRHandJointsUpdatedEventArgs eventArgs)
{
UpdateTypesNeededIfDirty();
if (m_TypesNeeded == XRFingerShapeTypes.None)
return true;
var fingerShape = eventArgs.hand.CalculateFingerShape(m_FingerID, m_TypesNeeded);
for (var index = 0; index < m_Targets.Length; ++index)
{
float value;
bool hasValue;
var target = targets[index];
switch (target.shapeType)
{
case XRFingerShapeType.FullCurl:
hasValue = fingerShape.TryGetFullCurl(out value);
break;
case XRFingerShapeType.BaseCurl:
hasValue = fingerShape.TryGetBaseCurl(out value);
break;
case XRFingerShapeType.TipCurl:
hasValue = fingerShape.TryGetTipCurl(out value);
break;
case XRFingerShapeType.Pinch:
hasValue = fingerShape.TryGetPinch(out value);
break;
case XRFingerShapeType.Spread:
hasValue = fingerShape.TryGetSpread(out value);
break;
default:
throw new ArgumentOutOfRangeException($"Finger shape type {target.shapeType} is invalid for finger shape target condition.");
}
if (!hasValue ||
value < (target.desired - target.lowerTolerance) ||
value > (target.desired + target.upperTolerance))
{
return false;
}
}
return true;
}
internal void UpdateTypesNeededIfDirty()
{
if (!m_TypesNeededDirty)
return;
m_TypesNeeded = XRFingerShapeTypes.None;
for (var index = 0; index < m_Targets.Length; index++)
m_TypesNeeded |= (XRFingerShapeTypes)(1 << (int)m_Targets[index].shapeType);
m_TypesNeededDirty = false;
}
}
}