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.
		
		
		
		
		
			
		
			
	
	
		
			309 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
		
		
			
		
	
	
			309 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
| 
								 
											1 year ago
										 
									 | 
							
								using System.Collections;
							 | 
						||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						||
| 
								 | 
							
								using UnityEngine;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace Autohand {
							 | 
						||
| 
								 | 
							
								    [DefaultExecutionOrder(999)]
							 | 
						||
| 
								 | 
							
								    public class WeightlessFollower : MonoBehaviour {
							 | 
						||
| 
								 | 
							
								        [HideInInspector]
							 | 
						||
| 
								 | 
							
								        public Transform follow1 = null;
							 | 
						||
| 
								 | 
							
								        [HideInInspector]
							 | 
						||
| 
								 | 
							
								        public Transform follow2 = null;
							 | 
						||
| 
								 | 
							
								        [HideInInspector]
							 | 
						||
| 
								 | 
							
								        public Hand hand1 = null;
							 | 
						||
| 
								 | 
							
								        [HideInInspector]
							 | 
						||
| 
								 | 
							
								        public Hand hand2 = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public Dictionary<Hand, Transform> heldMoveTo = new Dictionary<Hand, Transform>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [HideInInspector]
							 | 
						||
| 
								 | 
							
								        public float followPositionStrength = 30;
							 | 
						||
| 
								 | 
							
								        [HideInInspector]
							 | 
						||
| 
								 | 
							
								        public float followRotationStrength = 30;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [HideInInspector]
							 | 
						||
| 
								 | 
							
								        public float maxVelocity = 5;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [HideInInspector]
							 | 
						||
| 
								 | 
							
								        public Grabbable grab;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Transform _pivot = null;
							 | 
						||
| 
								 | 
							
								        public Transform pivot {
							 | 
						||
| 
								 | 
							
								            get {
							 | 
						||
| 
								 | 
							
								                if(!gameObject.activeInHierarchy)
							 | 
						||
| 
								 | 
							
								                    return null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if(_pivot == null) {
							 | 
						||
| 
								 | 
							
								                    _pivot = new GameObject().transform;
							 | 
						||
| 
								 | 
							
								                    _pivot.parent = transform.parent;
							 | 
						||
| 
								 | 
							
								                    _pivot.name = "WEIGHTLESS PIVOT";
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                return _pivot;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        internal Rigidbody body;
							 | 
						||
| 
								 | 
							
								        Transform moveTo = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        float startMass = 0;
							 | 
						||
| 
								 | 
							
								        float startDrag;
							 | 
						||
| 
								 | 
							
								        float startAngleDrag;
							 | 
						||
| 
								 | 
							
								        float startHandMass;
							 | 
						||
| 
								 | 
							
								        float startHandDrag;
							 | 
						||
| 
								 | 
							
								        float startHandAngleDrag;
							 | 
						||
| 
								 | 
							
								        bool useGravity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void Start() {
							 | 
						||
| 
								 | 
							
								            if(body == null)
							 | 
						||
| 
								 | 
							
								                body = GetComponent<Rigidbody>();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public virtual void Set(Hand hand, Grabbable grab) {
							 | 
						||
| 
								 | 
							
								            if (body == null)
							 | 
						||
| 
								 | 
							
								                body = grab.body;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(moveTo == null) {
							 | 
						||
| 
								 | 
							
								                moveTo = new GameObject().transform;
							 | 
						||
| 
								 | 
							
								                moveTo.name = gameObject.name + " FOLLOW POINT";
							 | 
						||
| 
								 | 
							
								                moveTo.parent = AutoHandExtensions.transformParent;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(!heldMoveTo.ContainsKey(hand)) {
							 | 
						||
| 
								 | 
							
								                heldMoveTo.Add(hand, new GameObject().transform);
							 | 
						||
| 
								 | 
							
								                heldMoveTo[hand].name = "HELD FOLLOW POINT";
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var tempTransform = AutoHandExtensions.transformRuler;
							 | 
						||
| 
								 | 
							
								            tempTransform.position = hand.transform.position;
							 | 
						||
| 
								 | 
							
								            tempTransform.rotation = hand.transform.rotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var tempTransformChild = AutoHandExtensions.transformRulerChild;
							 | 
						||
| 
								 | 
							
								            tempTransformChild.position = grab.rootTransform.position;
							 | 
						||
| 
								 | 
							
								            tempTransformChild.rotation = grab.rootTransform.rotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(grab.maintainGrabOffset) {
							 | 
						||
| 
								 | 
							
								                tempTransform.position = hand.moveTo.position + hand.grabPositionOffset;
							 | 
						||
| 
								 | 
							
								                tempTransform.rotation = hand.moveTo.rotation * hand.grabRotationOffset;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                tempTransform.position = hand.moveTo.position;
							 | 
						||
| 
								 | 
							
								                tempTransform.rotation = hand.moveTo.rotation;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            heldMoveTo[hand].parent = hand.moveTo;
							 | 
						||
| 
								 | 
							
								            heldMoveTo[hand].position = tempTransformChild.position;
							 | 
						||
| 
								 | 
							
								            heldMoveTo[hand].rotation = tempTransformChild.rotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(follow1 == null) {
							 | 
						||
| 
								 | 
							
								                follow1 = heldMoveTo[hand];
							 | 
						||
| 
								 | 
							
								                hand1 = hand;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if(follow2 == null) {
							 | 
						||
| 
								 | 
							
								                follow2 = heldMoveTo[hand];
							 | 
						||
| 
								 | 
							
								                hand2 = hand;
							 | 
						||
| 
								 | 
							
								                pivot.parent = body.transform;
							 | 
						||
| 
								 | 
							
								                pivot.position = Vector3.Lerp(hand1.handGrabPoint.position, hand2.handGrabPoint.position, 0.5f);
							 | 
						||
| 
								 | 
							
								                pivot.rotation = Quaternion.LookRotation((hand1.handGrabPoint.position - hand2.handGrabPoint.position).normalized, 
							 | 
						||
| 
								 | 
							
								                                 Vector3.Lerp(hand1.handGrabPoint.up, hand2.handGrabPoint.up, 0.5f));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (startMass == 0) {
							 | 
						||
| 
								 | 
							
								                startMass = body.mass;
							 | 
						||
| 
								 | 
							
								                startDrag = grab.preheldDrag;
							 | 
						||
| 
								 | 
							
								                startAngleDrag = grab.preheldAngularDrag;
							 | 
						||
| 
								 | 
							
								                useGravity = body.useGravity;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            startHandMass = hand.body.mass;
							 | 
						||
| 
								 | 
							
								            startHandDrag = hand.startDrag;
							 | 
						||
| 
								 | 
							
								            startHandAngleDrag = hand.startAngularDrag;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            body.mass = startHandMass;
							 | 
						||
| 
								 | 
							
								            body.drag = startHandDrag;
							 | 
						||
| 
								 | 
							
								            body.angularDrag = startHandAngleDrag;
							 | 
						||
| 
								 | 
							
								            body.useGravity = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            followPositionStrength = hand.followPositionStrength;
							 | 
						||
| 
								 | 
							
								            followRotationStrength = hand.followRotationStrength;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            maxVelocity = grab.maxHeldVelocity;
							 | 
						||
| 
								 | 
							
								            this.grab = grab;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            hand.OnBeforeReleased += OnHandReleased;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        void OnHandReleased(Hand hand, Grabbable grab){
							 | 
						||
| 
								 | 
							
								            if(heldMoveTo.ContainsKey(hand))
							 | 
						||
| 
								 | 
							
								                RemoveFollow(hand, heldMoveTo[hand]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public virtual void FixedUpdate() {
							 | 
						||
| 
								 | 
							
								            if(follow1 == null)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								             
							 | 
						||
| 
								 | 
							
								            MoveTo();
							 | 
						||
| 
								 | 
							
								            TorqueTo();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(grab.HeldCount() == 0)
							 | 
						||
| 
								 | 
							
								                Destroy(this);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected void SetMoveTo() {
							 | 
						||
| 
								 | 
							
								            if(follow1 == null || moveTo == null)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(follow2 != null) {
							 | 
						||
| 
								 | 
							
								                moveTo.position = Vector3.Lerp(hand1.moveTo.position, hand2.moveTo.position, 0.5f);
							 | 
						||
| 
								 | 
							
								                moveTo.rotation = Quaternion.LookRotation((hand1.moveTo.position - hand2.moveTo.position).normalized,
							 | 
						||
| 
								 | 
							
								                                 Vector3.Lerp(hand1.moveTo.up, hand2.moveTo.up, 0.5f));
							 | 
						||
| 
								 | 
							
								                moveTo.position -= pivot.position - pivot.parent.transform.position;
							 | 
						||
| 
								 | 
							
								                moveTo.rotation *= Quaternion.Inverse(pivot.localRotation);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                moveTo.position = follow1.position;
							 | 
						||
| 
								 | 
							
								                moveTo.rotation = follow1.rotation;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>Moves the hand to the controller position using physics movement</summary>
							 | 
						||
| 
								 | 
							
								        protected virtual void MoveTo() {
							 | 
						||
| 
								 | 
							
								            if(followPositionStrength <= 0 || moveTo == null)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            SetMoveTo();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var movePos = moveTo.position;
							 | 
						||
| 
								 | 
							
								            var distance = Vector3.Distance(movePos, transform.position);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            distance = Mathf.Clamp(distance, 0, 0.5f);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            SetVelocity(0.55f);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            void SetVelocity(float minVelocityChange) {
							 | 
						||
| 
								 | 
							
								                var velocityClamp = grab.maxHeldVelocity;
							 | 
						||
| 
								 | 
							
								                Vector3 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);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                var deltaOffset = Time.fixedDeltaTime / 0.011111f;
							 | 
						||
| 
								 | 
							
								                var inverseDeltaOffset = 0.011111f / Time.fixedDeltaTime;
							 | 
						||
| 
								 | 
							
								                body.drag = startDrag * inverseDeltaOffset;
							 | 
						||
| 
								 | 
							
								                var maxDelta = deltaOffset;
							 | 
						||
| 
								 | 
							
								                minVelocityChange *= deltaOffset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                body.velocity = new Vector3(
							 | 
						||
| 
								 | 
							
								                    Mathf.MoveTowards(body.velocity.x, vel.x, minVelocityChange + Mathf.Abs(body.velocity.x) * maxDelta),
							 | 
						||
| 
								 | 
							
								                    Mathf.MoveTowards(body.velocity.y, vel.y, minVelocityChange + Mathf.Abs(body.velocity.y) * maxDelta),
							 | 
						||
| 
								 | 
							
								                    Mathf.MoveTowards(body.velocity.z, vel.z, minVelocityChange + Mathf.Abs(body.velocity.z) * maxDelta)
							 | 
						||
| 
								 | 
							
								                );
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>Rotates the hand to the controller rotation using physics movement</summary>
							 | 
						||
| 
								 | 
							
								        protected virtual void TorqueTo() {
							 | 
						||
| 
								 | 
							
								            var moveRot = moveTo.rotation;
							 | 
						||
| 
								 | 
							
								            var delta = (moveRot * Quaternion.Inverse(body.rotation));
							 | 
						||
| 
								 | 
							
								            delta.ToAngleAxis(out float angle, out Vector3 axis);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(float.IsInfinity(axis.x))
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(angle > 180f)
							 | 
						||
| 
								 | 
							
								                angle -= 360f;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var multiLinear = Mathf.Deg2Rad * angle * followRotationStrength;
							 | 
						||
| 
								 | 
							
								            Vector3 angular = multiLinear * axis.normalized;
							 | 
						||
| 
								 | 
							
								            angle = Mathf.Abs(angle);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var angleStrengthOffset = Mathf.Lerp(1f, 1.5f, angle/16f);
							 | 
						||
| 
								 | 
							
								            var deltaOffset = Time.fixedDeltaTime / 0.011111f;
							 | 
						||
| 
								 | 
							
								            var inverseDeltaOffset = 0.011111f / Time.fixedDeltaTime;
							 | 
						||
| 
								 | 
							
								            body.angularDrag = Mathf.Lerp((startAngleDrag * 1.2f), startAngleDrag, angle/4f) * inverseDeltaOffset;
							 | 
						||
| 
								 | 
							
								            var maxDelta = followRotationStrength * 50f * angleStrengthOffset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            body.angularVelocity = new Vector3(
							 | 
						||
| 
								 | 
							
								                Mathf.MoveTowards(body.angularVelocity.x, angular.x, maxDelta),
							 | 
						||
| 
								 | 
							
								                Mathf.MoveTowards(body.angularVelocity.y, angular.y, maxDelta),
							 | 
						||
| 
								 | 
							
								                Mathf.MoveTowards(body.angularVelocity.z, angular.z, maxDelta)
							 | 
						||
| 
								 | 
							
								            );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        int CollisionCount() {
							 | 
						||
| 
								 | 
							
								            return grab.CollisionCount();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void RemoveFollow(Hand hand, Transform follow) {
							 | 
						||
| 
								 | 
							
								            hand.OnReleased -= OnHandReleased;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(this.follow1 == follow) {
							 | 
						||
| 
								 | 
							
								                this.follow1 = null;
							 | 
						||
| 
								 | 
							
								                hand1 = null;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if(follow2 == follow) {
							 | 
						||
| 
								 | 
							
								                follow2 = null;
							 | 
						||
| 
								 | 
							
								                hand2 = null;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(this.follow1 == null && follow2 != null) {
							 | 
						||
| 
								 | 
							
								                this.follow1 = follow2;
							 | 
						||
| 
								 | 
							
								                this.hand1 = hand2;
							 | 
						||
| 
								 | 
							
								                hand2 = null;
							 | 
						||
| 
								 | 
							
								                follow2 = null;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(this.follow1 == null && follow2 == null && !grab.beingGrabbed) {
							 | 
						||
| 
								 | 
							
								                if(body != null) {
							 | 
						||
| 
								 | 
							
								                    body.mass = startMass;
							 | 
						||
| 
								 | 
							
								                    body.drag = startDrag;
							 | 
						||
| 
								 | 
							
								                    body.angularDrag = startAngleDrag;
							 | 
						||
| 
								 | 
							
								                    body.useGravity = useGravity;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                Destroy(this);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            heldMoveTo.Remove(hand);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void OnDestroy()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if(moveTo != null)
							 | 
						||
| 
								 | 
							
								                Destroy(moveTo.gameObject);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            foreach(var transform in heldMoveTo)
							 | 
						||
| 
								 | 
							
								                Destroy(transform.Value.gameObject);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (body != null)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                body.mass = startMass;
							 | 
						||
| 
								 | 
							
								                body.drag = startDrag;
							 | 
						||
| 
								 | 
							
								                body.angularDrag = startAngleDrag;
							 | 
						||
| 
								 | 
							
								                body.useGravity = useGravity;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 |