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")] private Transform m_EffectorTransform; [SerializeField][FormerlySerializedAs("m_Effector")] private Transform m_TargetTransform; [SerializeField] private int m_TransformCount; [SerializeField] private Transform[] m_Transforms; [SerializeField] private Quaternion[] m_DefaultLocalRotations; [SerializeField] private Quaternion[] m_StoredLocalRotations; protected float[] m_Lengths; /// /// Get Set the Unity Transform used as IK Effector. /// public Transform effector { get { return m_EffectorTransform; } set { m_EffectorTransform = value; } } /// /// Get Set the Unity Transform used as IK Target. /// public Transform target { get { return m_TargetTransform; } set { m_TargetTransform = value; } } /// /// Get the Unity Transforms that are in the IK Chain. /// public Transform[] transforms { get { return 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; } } private 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 { return m_TransformCount; } set { m_TransformCount = Mathf.Max(0, value); } } /// /// Returns true if the IK Chain is valid. False otherwise. /// public bool isValid { get { return Validate(); } } /// /// Gets the length of the IK Chain. /// public float[] lengths { get { if(isValid) { PrepareLengths(); return m_Lengths; } return null; } } private 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; if (target && IKUtility.IsDescendentOf(target, rootTransform)) return false; return true; } /// /// 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; int index = transformCount - 1; while (currentTransform && index >= 0) { m_Transforms[index] = currentTransform; m_DefaultLocalRotations[index] = currentTransform.localRotation; currentTransform = currentTransform.parent; --index; } } private void PrepareLengths() { var currentTransform = effector; int 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 (int i = 0; i < count; ++i) m_Transforms[i].localRotation = m_DefaultLocalRotations[i]; } /// /// Explicitly stores the local rotation /// public void StoreLocalRotations() { for (int 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 (int i = 0; i < count; ++i) m_Transforms[i].localRotation = Quaternion.Slerp(m_StoredLocalRotations[i], m_Transforms[i].localRotation, finalWeight); } } }