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.

193 lines
9.2 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Autohand
{
[RequireComponent(typeof(Grabbable)), DefaultExecutionOrder(10)]
public class GrabbableHeldJoint : MonoBehaviour
{
[Tooltip("The grabbable that this grabbable is connected to")]
public Grabbable connectedGrabbable;
[Tooltip("Offsets the center of this joint")]
public Vector3 pivotOffset;
[Tooltip("This will multiply the hands strength while holding this grabbable to give it more or less positional priority while holding this joint as a second hand (good to reduce when you dont want this joint having movement priority while being held)")]
[Min(0.1f)]
public float heldMassScale = 1f;
[Space]
[Tooltip("The maximum distance this joint is allowed to move in the local positive x-axis")]
public float xMaxLimit = 0f;
[Tooltip("The maximum distance this joint is allowed to move in the local negative x-axis")]
public float xMinLimit = 0f;
[Tooltip("This will force the joint back into its center position based on the given spring strength while not being held along this axis")]
public float xSpring = 0f;
[Space]
[Tooltip("The maximum distance this joint is allowed to move in the local positive y-axis")]
public float yMaxLimit = 0f;
[Tooltip("The maximum distance this joint is allowed to move in the local negative y-axis")]
public float yMinLimit = 0f;
[Tooltip("This will force the joint back into its center position based on the given spring strength while not being held along this axis")]
public float ySpring = 0f;
[Space]
[Tooltip("The maximum distance this joint is allowed to move in the local positive z-axis")]
public float zMaxLimit = 0f;
[Tooltip("The maximum distance this joint is allowed to move in the local negative z-axis")]
public float zMinLimit = 0f;
[Tooltip("This will force the joint back into its center position based on the given spring strength while not being held along this axis")]
public float zSpring = 0f;
[Space]
[Range(0, 1), Tooltip("The percentage from the min/max distance needed to trigger the event, good for creating a buffer for the event to trigger slightly before the max range to help prevent missed event")]
public float eventOffset = 0.05f;
public UnityHandGrabEvent OnMinDistanceEvent;
public UnityHandGrabEvent OnMaxDistanceEvent;
bool triggeredMaxEvent;
bool triggeredMinEvent;
Vector3 handLocalPosition;
Vector3 localPosition;
Vector3 localTargetPosition;
Vector3 localStartPosition;
Grabbable grabbable;
Vector3 localOrigin;
Vector3 localStartOrigin;
Hand jointHand;
bool grabFrame;
bool started = false;
public void Start()
{
if(started)
return;
ResetOrigin();
if(grabbable == null) {
grabbable = GetComponent<Grabbable>();
grabbable.OnGrabEvent += OnGrabbed;
grabbable.OnReleaseEvent += OnReleased;
}
grabbable.singleHandOnly = true;
if(xMinLimit == 0 && yMinLimit == 0 && zMinLimit == 0)
triggeredMinEvent = true;
started = true;
}
public void ResetOrigin()
{
localOrigin = connectedGrabbable.rootTransform.InverseTransformPoint(transform.position) + pivotOffset;
localStartOrigin = localOrigin;
}
internal void OnGrabbed(Hand hand, Grabbable grab)
{
jointHand = hand;
hand.body.mass *= heldMassScale;
localOrigin = hand.heldJoint.connectedAnchor + pivotOffset;
localTargetPosition = new Vector3(
Mathf.Clamp(handLocalPosition.x, localOrigin.x + xMinLimit, localOrigin.x + xMaxLimit),
Mathf.Clamp(handLocalPosition.y, localOrigin.y + yMinLimit, localOrigin.y + yMaxLimit),
Mathf.Clamp(handLocalPosition.z, localOrigin.z + zMinLimit, localOrigin.z + zMaxLimit)
);
localTargetPosition += pivotOffset;
grabFrame = true;
}
void OnReleased(Hand hand, Grabbable grab)
{
jointHand = null;
hand.body.mass /= heldMassScale;
localOrigin = localStartOrigin;
}
private void FixedUpdate()
{
if(grabFrame) {
grabFrame = false;
return;
}
UpdateJoint();
}
public void SetJointMax() {
transform.position = connectedGrabbable.rootTransform.TransformPoint(localOrigin + pivotOffset + new Vector3(xMaxLimit, yMaxLimit, zMaxLimit));
}
public void SetJointMin() {
transform.position = connectedGrabbable.rootTransform.TransformPoint(localOrigin + pivotOffset + new Vector3(xMinLimit, yMinLimit, zMinLimit));
}
public void UpdateJoint()
{
if (connectedGrabbable.HeldCount() > 0 && grabbable.HeldCount(false, false, true) > 0 && jointHand != null)
{
handLocalPosition = jointHand.heldJoint.connectedBody.transform.InverseTransformPoint(jointHand.moveTo.position) + pivotOffset;
localPosition = jointHand.heldJoint.connectedAnchor + pivotOffset;
localTargetPosition = new Vector3(
Mathf.MoveTowards(localPosition.x, Mathf.Clamp(handLocalPosition.x, localOrigin.x + xMinLimit, localOrigin.x + xMaxLimit), 1f),
Mathf.MoveTowards(localPosition.y, Mathf.Clamp(handLocalPosition.y, localOrigin.y + yMinLimit, localOrigin.y + yMaxLimit), 1f),
Mathf.MoveTowards(localPosition.z, Mathf.Clamp(handLocalPosition.z, localOrigin.z + zMinLimit, localOrigin.z + zMaxLimit), 1f)
);
if(localPosition != localTargetPosition) {
//Vector3 globalTargetPosition = connectedGrabbable.rootTransform.TransformPoint(localTargetPosition - jointHand.handGrabPoint.localPosition);
transform.localPosition += (localTargetPosition - localPosition); // Adjusting position with pivot offset
transform.localPosition = new Vector3(
Mathf.Clamp(transform.localPosition.x, localStartOrigin.x + xMinLimit, localStartOrigin.x + xMaxLimit),
Mathf.Clamp(transform.localPosition.y, localStartOrigin.y + yMinLimit, localStartOrigin.y + yMaxLimit),
Mathf.Clamp(transform.localPosition.z, localStartOrigin.z + zMinLimit, localStartOrigin.z + zMaxLimit)
);
jointHand.heldJoint.connectedAnchor += (localTargetPosition - localPosition);
jointHand.handGrabPoint.localPosition += (localTargetPosition - localPosition);
}
}
else
{
Vector3 localPosition = connectedGrabbable.transform.InverseTransformPoint(transform.position) + pivotOffset;
Vector3 localTargetPosition = new Vector3(
Mathf.MoveTowards(localPosition.x, localOrigin.x, Time.fixedDeltaTime * xSpring),
Mathf.MoveTowards(localPosition.y, localOrigin.y, Time.fixedDeltaTime * ySpring),
Mathf.MoveTowards(localPosition.z, localOrigin.z, Time.fixedDeltaTime * zSpring)
);
if(transform.localPosition != localOrigin)
transform.position = connectedGrabbable.rootTransform.TransformPoint(localTargetPosition);
}
if(OnMaxDistanceEvent != null) {
var localPos = connectedGrabbable.rootTransform.InverseTransformPoint(transform.position);
bool greaterOrEqual =
localPos.x >= localStartOrigin.x + xMaxLimit - xMaxLimit * eventOffset - 0.001f &&
localPos.y >= localStartOrigin.y + yMaxLimit - yMaxLimit * eventOffset - 0.001f &&
localPos.z >= localStartOrigin.z + zMaxLimit - zMaxLimit * eventOffset - 0.001f;
if(greaterOrEqual && !triggeredMaxEvent) {
OnMaxDistanceEvent.Invoke(jointHand, connectedGrabbable);
triggeredMaxEvent = true;
triggeredMinEvent = false;
}
}
if(OnMinDistanceEvent != null) {
var localPos = connectedGrabbable.rootTransform.InverseTransformPoint(transform.position);
bool lessOrEqual =
localPos.x <= localStartOrigin.x + xMinLimit - xMinLimit * eventOffset + 0.001f &&
localPos.y <= localStartOrigin.y + yMinLimit - yMinLimit * eventOffset + 0.001f &&
localPos.z <= localStartOrigin.z + zMinLimit - zMinLimit * eventOffset + 0.001f;
if(lessOrEqual && !triggeredMinEvent) {
OnMinDistanceEvent.Invoke(jointHand, connectedGrabbable);
triggeredMinEvent = true;
triggeredMaxEvent = false;
}
}
}
}
}