using System;
using UnityEngine.Scripting.APIUpdating;
using UnityEngine.Serialization;
namespace UnityEngine.U2D.IK
{
///
/// Class for storing data for a 2D IK Chain.
///
[MovedFrom("UnityEngine.Experimental.U2D.IK")]
[Serializable]
public class IKChain2D
{
[SerializeField]
[FormerlySerializedAs("m_Target")]
Transform m_EffectorTransform;
[SerializeField]
[FormerlySerializedAs("m_Effector")]
Transform m_TargetTransform;
[SerializeField]
int m_TransformCount;
[SerializeField]
Transform[] m_Transforms;
[SerializeField]
Quaternion[] m_DefaultLocalRotations;
[SerializeField]
Quaternion[] m_StoredLocalRotations;
///
/// Lengths of IK Chain.
///
/// Array of lengths in the IK Chain.
protected float[] m_Lengths;
///
/// Get Set the Unity Transform used as IK Effector.
///
public Transform effector
{
get => m_EffectorTransform;
set => m_EffectorTransform = value;
}
///
/// Get Set the Unity Transform used as IK Target.
///
public Transform target
{
get => m_TargetTransform;
set => m_TargetTransform = value;
}
///
/// Get the Unity Transforms that are in the IK Chain.
///
public Transform[] transforms => m_Transforms;
///
/// Get the root Unity Transform for the IK Chain.
///
public Transform rootTransform
{
get
{
if (m_Transforms != null && transformCount > 0 && m_Transforms.Length == transformCount)
return m_Transforms[0];
return null;
}
}
Transform lastTransform
{
get
{
if (m_Transforms != null && transformCount > 0 && m_Transforms.Length == transformCount)
return m_Transforms[transformCount - 1];
return null;
}
}
///
/// Get and Set the number of Unity Transforms in the IK Chain.
///
public int transformCount
{
get => m_TransformCount;
set => m_TransformCount = Mathf.Max(0, value);
}
///
/// Returns true if the IK Chain is valid. False otherwise.
///
public bool isValid => Validate();
///
/// Gets the length of the IK Chain.
///
public float[] lengths
{
get
{
if (isValid)
{
PrepareLengths();
return m_Lengths;
}
return null;
}
}
bool Validate()
{
if (effector == null)
return false;
if (transformCount == 0)
return false;
if (m_Transforms == null || m_Transforms.Length != transformCount)
return false;
if (m_DefaultLocalRotations == null || m_DefaultLocalRotations.Length != transformCount)
return false;
if (m_StoredLocalRotations == null || m_StoredLocalRotations.Length != transformCount)
return false;
if (rootTransform == null)
return false;
if (lastTransform != effector)
return false;
return !target || !IKUtility.IsDescendentOf(target, rootTransform);
}
///
/// Initialize the IK Chain.
///
public void Initialize()
{
if (effector == null || transformCount == 0 || IKUtility.GetAncestorCount(effector) < transformCount - 1)
return;
m_Transforms = new Transform[transformCount];
m_DefaultLocalRotations = new Quaternion[transformCount];
m_StoredLocalRotations = new Quaternion[transformCount];
var currentTransform = effector;
var index = transformCount - 1;
while (currentTransform && index >= 0)
{
m_Transforms[index] = currentTransform;
m_DefaultLocalRotations[index] = currentTransform.localRotation;
currentTransform = currentTransform.parent;
--index;
}
}
void PrepareLengths()
{
var currentTransform = effector;
var index = transformCount - 1;
if (m_Lengths == null || m_Lengths.Length != transformCount - 1)
m_Lengths = new float[transformCount - 1];
while (currentTransform && index >= 0)
{
if (currentTransform.parent && index > 0)
m_Lengths[index - 1] = (currentTransform.position - currentTransform.parent.position).magnitude;
currentTransform = currentTransform.parent;
--index;
}
}
///
/// Restores IK Chain to it's default pose.
///
/// True to constrain the target rotation. False otherwise.
public void RestoreDefaultPose(bool targetRotationIsConstrained)
{
var count = targetRotationIsConstrained ? transformCount : transformCount - 1;
for (var i = 0; i < count; ++i)
m_Transforms[i].localRotation = m_DefaultLocalRotations[i];
}
///
/// Explicitly stores the local rotation
///
public void StoreLocalRotations()
{
for (var i = 0; i < m_Transforms.Length; ++i)
m_StoredLocalRotations[i] = m_Transforms[i].localRotation;
}
///
/// Blend between Forward Kinematics and Inverse Kinematics.
///
/// Weight for blend
/// True to constrain target rotation. False otherwise.
public void BlendFkToIk(float finalWeight, bool targetRotationIsConstrained)
{
var count = targetRotationIsConstrained ? transformCount : transformCount - 1;
for (var i = 0; i < count; ++i)
m_Transforms[i].localRotation = Quaternion.Slerp(m_StoredLocalRotations[i], m_Transforms[i].localRotation, finalWeight);
}
}
}