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); } } }