using UnityEngine.Scripting.APIUpdating; namespace UnityEngine.U2D.IK { /// /// Utility for 2D based Cyclic Coordinate Descent (CCD) IK Solver. /// [MovedFrom("UnityEngine.Experimental.U2D.IK")] public static class CCD2D { /// /// Solve IK Chain based on CCD. /// /// Target position. /// Forward vector for solver. /// Solver iteration count. /// Target position's tolerance. /// Velocity towards target position. /// Chain positions. /// Returns true if solver successfully completes within iteration limit. False otherwise. public static bool Solve(Vector3 targetPosition, Vector3 forward, int solverLimit, float tolerance, float velocity, ref Vector3[] positions) { var last = positions.Length - 1; var iterations = 0; var sqrTolerance = tolerance * tolerance; var sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude; while (sqrDistanceToTarget > sqrTolerance) { DoIteration(targetPosition, forward, last, velocity, ref positions); sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude; if (++iterations >= solverLimit) break; } return iterations != 0; } static void DoIteration(Vector3 targetPosition, Vector3 forward, int last, float velocity, ref Vector3[] positions) { for (var i = last - 1; i >= 0; --i) { var toTarget = targetPosition - positions[i]; var toLast = positions[last] - positions[i]; var angle = Vector3.SignedAngle(toLast, toTarget, forward); angle = Mathf.Lerp(0f, angle, velocity); var deltaRotation = Quaternion.AngleAxis(angle, forward); for (var j = last; j > i; --j) positions[j] = RotatePositionFrom(positions[j], positions[i], deltaRotation); } } static Vector3 RotatePositionFrom(Vector3 position, Vector3 pivot, Quaternion rotation) { var v = position - pivot; v = rotation * v; return pivot + v; } } }