using System.Collections; using System.Collections.Generic; using UnityEngine; public class InverseKinematics : MonoBehaviour { private Material lineMaterial; private Dictionary linePoints = new Dictionary(); public bool SoftEnabled = true; public Transform upperArm; public Transform forearm; public Transform hand; public Transform elbow; public Transform target; [Space(20)] public Vector3 uppperArm_OffsetRotation; public Vector3 forearm_OffsetRotation; public Vector3 hand_OffsetRotation; [Space(20)] public bool handMatchesTargetRotation = true; [Space(20)] public bool linesVisible = true; public bool forceLinesInvisible = true; float angle; float upperArm_Length; float forearm_Length; float arm_Length; float targetDistance; float adyacent; public void SpawnLines(Color specialColor) { lineMaterial = new Material(Shader.Find("Legacy Shaders/Particles/Alpha Blended Premultiply")); NewLine(upperArm, elbow, 0.005f, Color.yellow); NewLine(elbow, target, 0.005f, Color.yellow); NewLine(upperArm, target, 0.005f, Color.white); NewLine(forearm, elbow, 0.01f, specialColor); } void NewLine(Transform point1, Transform point2, float width, Color color) { GameObject go = new GameObject("line"); go.layer = 5; go.transform.SetParent(this.transform); var lr = go.AddComponent(); lr.startWidth = lr.endWidth = width; lr.startColor = lr.endColor = color; lr.sharedMaterial = lineMaterial; linePoints.Add(go, new Transform[] { point1, point2 }); } void UpdateLines() { foreach(var kv in linePoints) { var lr = kv.Key.GetComponent(); if (!SoftEnabled) { if(lr.enabled != SoftEnabled) { lr.enabled = SoftEnabled; } } else if((lr.enabled != linesVisible) || (lr.enabled && forceLinesInvisible)) { if(forceLinesInvisible) { lr.enabled = false; } else { lr.enabled = linesVisible; } } for (int i = 0; i < kv.Value.Length; i++) { lr.SetPosition(i, kv.Value[i].position); } } } // Update is called once per frame void LateUpdate () { if(upperArm != null && forearm != null && hand != null && elbow != null && target != null) { if (SoftEnabled) { upperArm_Length = Vector3.Distance(upperArm.position, forearm.position); forearm_Length = Vector3.Distance(forearm.position, hand.position); arm_Length = upperArm_Length + forearm_Length; targetDistance = Vector3.Distance(upperArm.position, target.position); targetDistance = Mathf.Min(targetDistance, arm_Length - arm_Length * 0.001f); upperArm.LookAt(target, elbow.position - upperArm.position); upperArm.Rotate(uppperArm_OffsetRotation); Vector3 cross = Vector3.Cross(elbow.position - upperArm.position, forearm.position - upperArm.position); adyacent = ((upperArm_Length * upperArm_Length) - (forearm_Length * forearm_Length) + (targetDistance * targetDistance)) / (2 * targetDistance); angle = Mathf.Acos(adyacent / upperArm_Length) * Mathf.Rad2Deg; if (float.IsNaN(angle)) { return; } Vector3 oldPosition = upperArm.localPosition; upperArm.RotateAround(upperArm.position, cross, -angle); upperArm.localPosition = oldPosition; forearm.LookAt(target, cross); forearm.Rotate(forearm_OffsetRotation); if (handMatchesTargetRotation) { hand.rotation = target.rotation; hand.Rotate(hand_OffsetRotation); } } else { //target.position = hand.position; //target.rotation = hand.rotation; //target.Rotate(-hand_OffsetRotation); //elbow.position = forearm.position; } UpdateLines(); } } private void OnDestroy() { Destroy(lineMaterial); foreach(var i in linePoints) { Destroy(i.Key); } Destroy(elbow.gameObject); Destroy(target.gameObject); } void OnDrawGizmos(){ if (linesVisible) { if(upperArm != null && elbow != null && hand != null && target != null && elbow != null){ Gizmos.color = Color.gray; Gizmos.DrawLine (upperArm.position, forearm.position); Gizmos.DrawLine (forearm.position, hand.position); Gizmos.color = Color.red; Gizmos.DrawLine (upperArm.position, target.position); Gizmos.color = Color.blue; Gizmos.DrawLine (forearm.position, elbow.position); } } } }