using System.Collections.Generic;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.U2D.IK
{
///
/// Component responsible for 2D Limb IK.
///
[MovedFrom("UnityEngine.Experimental.U2D.IK")]
[Solver2DMenuAttribute("Limb")]
[IconAttribute(IconUtility.IconPath + "Animation.IKLimb.png")]
public sealed class LimbSolver2D : Solver2D
{
[SerializeField]
IKChain2D m_Chain = new IKChain2D();
[SerializeField]
bool m_Flip;
Vector3[] m_Positions = new Vector3[3];
float[] m_Lengths = new float[2];
float[] m_Angles = new float[2];
///
/// Get and set the flip property.
///
public bool flip
{
get => m_Flip;
set => m_Flip = value;
}
///
/// Initializes the solver.
///
protected override void DoInitialize()
{
m_Chain.transformCount = m_Chain.effector == null || IKUtility.GetAncestorCount(m_Chain.effector) < 2 ? 0 : 3;
base.DoInitialize();
}
///
/// Returns the number of chains in the solver.
///
/// Returns 1, because Limb Solver has only one chain.
protected override int GetChainCount() => 1;
///
/// Gets the chain in the solver at index.
///
/// Index to query. Not used in this override.
/// Returns IKChain2D for the Solver.
public override IKChain2D GetChain(int index) => m_Chain;
///
/// Prepares the data required for updating the solver.
///
protected override void DoPrepare()
{
var lengths = m_Chain.lengths;
m_Positions[0] = m_Chain.transforms[0].position;
m_Positions[1] = m_Chain.transforms[1].position;
m_Positions[2] = m_Chain.transforms[2].position;
m_Lengths[0] = lengths[0];
m_Lengths[1] = lengths[1];
}
///
/// Updates the IK and sets the chain's transform positions.
///
/// List of target positions.
protected override void DoUpdateIK(List targetPositions)
{
var targetPosition = targetPositions[0];
var upperLimb = m_Chain.transforms[0];
var lowerLimb = m_Chain.transforms[1];
var effector = m_Chain.effector;
var targetLocalPosition2D = (Vector2)upperLimb.InverseTransformPoint(targetPosition);
targetPosition = upperLimb.TransformPoint(targetLocalPosition2D);
if (targetLocalPosition2D.sqrMagnitude > 0f && Limb.Solve(targetPosition, m_Lengths, m_Positions, ref m_Angles))
{
var upperLimbRotation = Quaternion.FromToRotation(Vector3.right, targetLocalPosition2D) * Quaternion.FromToRotation((Vector2)lowerLimb.localPosition, Vector3.right);
upperLimbRotation *= Quaternion.AngleAxis((flip ? -1f : 1f) * m_Angles[0], Vector3.forward);
upperLimb.localRotation *= upperLimbRotation;
var loweLimbRotation = Quaternion.FromToRotation(Vector3.right, lowerLimb.InverseTransformPoint(targetPosition)) * Quaternion.FromToRotation((Vector2)effector.localPosition, Vector3.right);
m_Chain.transforms[1].localRotation *= loweLimbRotation;
}
}
}
}