You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
4.7 KiB
C#
131 lines
4.7 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Autohand{
|
|
[RequireComponent(typeof(Rigidbody)), DefaultExecutionOrder(-1)]
|
|
public class PhysicsFollower : MonoBehaviour{
|
|
[Header("Follow Settings"), Space]
|
|
[Tooltip("Follow target, the hand will always try to match this transforms rotation and position with rigidbody movements")]
|
|
public Transform follow;
|
|
|
|
[Tooltip("Stops hand physics follow - to freeze from all forces change rigidbody to kinematic or change rigidbody constraints")]
|
|
public bool freezePos = false;
|
|
|
|
[Tooltip("Stops hand physics follow - to freeze from all forces change rigidbody to kinematic or change rigidbody constraints")]
|
|
public bool freezeRot = false;
|
|
|
|
[Tooltip("This will offset the position without offsetting the rotation pivot")]
|
|
public Vector3 followPositionOffset;
|
|
public Vector3 rotationOffset;
|
|
|
|
[Tooltip("Follow target speed (This will cause jittering if turned too high)"), Min(0)]
|
|
public float followPositionStrength = 30;
|
|
|
|
[Tooltip("Follow target rotation speed (This will cause jittering if turned too high)"), Min(0)]
|
|
public float followRotationStrength = 30;
|
|
|
|
[Tooltip("The maximum allowed velocity of the hand"), Min(0)]
|
|
public float maxVelocity = 5;
|
|
|
|
|
|
internal Rigidbody body;
|
|
Transform moveTo;
|
|
|
|
public void Start() {
|
|
Set();
|
|
}
|
|
|
|
public virtual void Set() {
|
|
if(moveTo == null){
|
|
moveTo = new GameObject().transform;
|
|
moveTo.name = gameObject.name + " FOLLOW POINT";
|
|
moveTo.parent = follow.parent;
|
|
moveTo.position = follow.transform.position;
|
|
moveTo.rotation = follow.transform.rotation;
|
|
body = GetComponent<Rigidbody>();
|
|
}
|
|
}
|
|
|
|
public void Update() {
|
|
OnUpdate();
|
|
}
|
|
|
|
protected virtual void OnUpdate() {
|
|
if(follow == null)
|
|
return;
|
|
|
|
//Sets [Move To] Object
|
|
moveTo.position = follow.position + transform.rotation*followPositionOffset;
|
|
moveTo.rotation = follow.rotation * Quaternion.Euler(rotationOffset);
|
|
}
|
|
|
|
|
|
public void FixedUpdate() {
|
|
OnFixedUpdate();
|
|
}
|
|
|
|
protected virtual void OnFixedUpdate() {
|
|
if(follow == null)
|
|
return;
|
|
|
|
//Sets [Move To] Object
|
|
moveTo.position = follow.position + transform.rotation*followPositionOffset;
|
|
moveTo.rotation = follow.rotation * Quaternion.Euler(rotationOffset);
|
|
|
|
//Calls physics movements
|
|
if(!freezePos) MoveTo();
|
|
if(!freezeRot) TorqueTo();
|
|
|
|
}
|
|
|
|
|
|
/// <summary>Moves the hand to the controller position using physics movement</summary>
|
|
internal virtual void MoveTo() {
|
|
if(followPositionStrength <= 0)
|
|
return;
|
|
|
|
var movePos = moveTo.position;
|
|
var distance = Vector3.Distance(movePos, transform.position);
|
|
var velocityClamp = maxVelocity;
|
|
|
|
|
|
//Sets velocity linearly based on distance from hand
|
|
var vel = (movePos - transform.position).normalized * followPositionStrength * distance;
|
|
vel.x = Mathf.Clamp(vel.x, -velocityClamp, velocityClamp);
|
|
vel.y = Mathf.Clamp(vel.y, -velocityClamp, velocityClamp);
|
|
vel.z = Mathf.Clamp(vel.z, -velocityClamp, velocityClamp);
|
|
body.velocity = vel;
|
|
}
|
|
|
|
|
|
/// <summary>Rotates the hand to the controller rotation using physics movement</summary>
|
|
internal virtual void TorqueTo() {
|
|
var toRot = moveTo.rotation;
|
|
float angleDist = Quaternion.Angle(body.rotation, toRot);
|
|
Quaternion desiredRotation = Quaternion.Lerp(body.rotation, toRot, Mathf.Clamp(angleDist, 0, 2) / 4f);
|
|
|
|
var kp = 90f * followRotationStrength;
|
|
var kd = 60f;
|
|
Vector3 x;
|
|
float xMag;
|
|
Quaternion q = desiredRotation * Quaternion.Inverse(transform.rotation);
|
|
q.ToAngleAxis(out xMag, out x);
|
|
x.Normalize();
|
|
x *= Mathf.Deg2Rad;
|
|
Vector3 pidv = kp * x * xMag - kd * body.angularVelocity;
|
|
Quaternion rotInertia2World = body.inertiaTensorRotation * transform.rotation;
|
|
pidv = Quaternion.Inverse(rotInertia2World) * pidv;
|
|
pidv.Scale(body.inertiaTensor);
|
|
pidv = rotInertia2World * pidv;
|
|
body.AddTorque(pidv);
|
|
}
|
|
|
|
private void OnDestroy() {
|
|
Destroy(moveTo.gameObject);
|
|
}
|
|
}
|
|
|
|
|
|
}
|