157 lines
4.4 KiB
C#
157 lines
4.4 KiB
C#
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
public class InverseKinematics : MonoBehaviour {
|
|||
|
private Material lineMaterial;
|
|||
|
private Dictionary<GameObject, Transform[]> linePoints = new Dictionary<GameObject, Transform[]>();
|
|||
|
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<LineRenderer>();
|
|||
|
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<LineRenderer>();
|
|||
|
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);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|