You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
533 lines
22 KiB
533 lines
22 KiB
using DG.Tweening; |
|
using UnityEditor; |
|
using UnityEngine; |
|
using System.Linq; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
using System; |
|
using UnityEngine.Events; |
|
#if MIRROR |
|
using Mirror; |
|
#endif |
|
|
|
|
|
namespace UDE_HAND_INTERACTION |
|
{ |
|
public class InteractableObject : MonoBehaviour |
|
{ |
|
[HideInInspector] |
|
public GameObject DefaultVirtualHand; |
|
[HideInInspector] |
|
public GameObject Hand { get; private set; } |
|
private GameObject _VirtualHand; |
|
private GameObject CalculateGameobj; |
|
private GameObject CalculateGameobjVirtualHand; |
|
private Vector3 PosOffset; |
|
private Quaternion RotOffset; |
|
|
|
private bool follow = false; |
|
public bool IsFollow => follow; |
|
private bool RegularTransfer = true; |
|
|
|
[HideInInspector] |
|
public int InteractPriority; |
|
|
|
[Space] |
|
public UnityEvent WhenObjInteract; |
|
public UnityEvent WhenObjDisable; |
|
|
|
public bool enablePhysicalProperties; |
|
public bool enableMotionTrace; |
|
public float traceVisibleSeconds = 5f; |
|
|
|
[Serializable, SerializeField] |
|
public struct HandInteractionPlans |
|
{ |
|
[SerializeField] |
|
public string Name; |
|
[SerializeField] |
|
public HandInteraction[] handInteractions; |
|
|
|
public HandInteractionPlans(string name, HandInteraction[] interactions) |
|
{ |
|
Name = name; |
|
handInteractions = interactions; |
|
} |
|
} |
|
|
|
[SerializeField, Space] |
|
public HandInteraction[] HandInteractions; |
|
[HideInInspector] |
|
public HandInteraction[] AllInteractions { get; private set; } |
|
|
|
public bool enableInteractionPlans; |
|
|
|
[SerializeField] |
|
public HandInteractionPlans[] InteractionPlan; |
|
|
|
[HideInInspector] |
|
public ObjectFollowType objectFollowType; |
|
[HideInInspector] |
|
public float TrackingTime; |
|
[HideInInspector] |
|
public float TrackingDistance; |
|
[HideInInspector] |
|
public float MovingOnTime; |
|
[HideInInspector] |
|
public Transform InsideOperationPart; |
|
private GameObject[] TempHand = { null, null }; |
|
|
|
private Vector3 PreActivePos = Vector3.zero; |
|
private Quaternion PreActiveRot = Quaternion.identity; |
|
private bool BackReset = false; |
|
private Tween[] SlowLocalTween = new Tween[2]; |
|
private Tween DistanceCurveTween; |
|
|
|
private Rigidbody _body; |
|
private bool hasRigid = false; |
|
private bool onThrow = false; |
|
private int FixedTimeIndedx = 1; |
|
public enum ObjectFollowType |
|
{ |
|
Instant, |
|
SlowMove, |
|
Chasing, |
|
NoPose, |
|
Natural, |
|
Distance |
|
} |
|
|
|
public InteractableObjectOutline interactableObjectOutline => GetComponent<InteractableObjectOutline>(); |
|
|
|
public bool SetInteractSound = false; |
|
|
|
void Start() |
|
{ |
|
if (CalculateGameobj == null) |
|
{ |
|
CalculateGameobj = new("CalculateGameobj"); |
|
CalculateGameobj.transform.parent = transform; |
|
} |
|
if (CalculateGameobjVirtualHand == null) |
|
{ |
|
CalculateGameobjVirtualHand = new("CalculateGameobjVirtualHand"); |
|
CalculateGameobjVirtualHand.transform.parent = CalculateGameobj.transform; |
|
} |
|
AutoCheckHand(); |
|
if(HandInteractions.Length == 0 && !enableInteractionPlans) |
|
{ |
|
objectFollowType = ObjectFollowType.NoPose; |
|
} |
|
|
|
if(enablePhysicalProperties) |
|
{ |
|
_body = GetComponent<Rigidbody>(); |
|
hasRigid = _body != null; |
|
} |
|
|
|
if(TryGetComponent<AudioSource>(out var audio) && SetInteractSound) |
|
{ |
|
WhenObjInteract.AddListener(() => { audio.Play(); }); |
|
} |
|
|
|
#if UNITY_EDITOR |
|
if (DefaultVirtualHand == null) |
|
{ |
|
DefaultVirtualHand = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/SDK/Interaction SDK/Prefabs/DefaultVirtualHand.prefab"); |
|
} |
|
#endif |
|
} |
|
|
|
void Update() |
|
{ |
|
if (BackReset && transform.position != PreActivePos) |
|
{ |
|
transform.SetPositionAndRotation(PreActivePos, PreActiveRot); |
|
BackReset = false; |
|
} |
|
} |
|
|
|
private void FixedUpdate() |
|
{ |
|
if (onThrow && hasRigid && enableMotionTrace) |
|
{ |
|
float time = Time.fixedDeltaTime * FixedTimeIndedx; |
|
GetComponent<LineRenderer>().positionCount = FixedTimeIndedx; |
|
GetComponent<LineRenderer>().SetPosition(FixedTimeIndedx - 1, transform.position); |
|
FixedTimeIndedx++; |
|
if(time >= traceVisibleSeconds) |
|
{ |
|
onThrow = false; |
|
GetComponent<LineRenderer>().positionCount = 0; |
|
} |
|
} |
|
} |
|
|
|
public void HandActive(GameObject hand, HandInteraction handInteraction, Vector3 CalculatedRegularPoint) |
|
{ |
|
if (ActiveLock) return; |
|
Hand = hand; |
|
PreActivePos = transform.position; |
|
PreActiveRot = transform.rotation; |
|
|
|
if (hasRigid && !follow) |
|
{ |
|
FixedTimeIndedx = 1; |
|
onThrow = false; |
|
_body.useGravity = false; |
|
_body.isKinematic = true; |
|
Hand.GetComponent<Rigidbody>().isKinematic = true; |
|
} |
|
if (handInteraction == null) |
|
{ |
|
transform.parent = Hand.transform; |
|
follow = true; |
|
WhenObjInteract.Invoke(); |
|
DestroyImmediate(_body); |
|
Hand.GetComponent<Rigidbody>().isKinematic = false; |
|
return; |
|
} |
|
|
|
_VirtualHand = handInteraction.gameObject; |
|
|
|
if(CalculatedRegularPoint != Vector3.zero && RegularTransfer) |
|
{ |
|
if(handInteraction.TryGetComponent<RegularShapeFit>(out var regular)) |
|
{ |
|
if(regular.SpecialSphere) |
|
{ |
|
_VirtualHand.transform.RotateAround(CalculatedRegularPoint, hand.transform.right, hand.transform.eulerAngles.x - _VirtualHand.transform.eulerAngles.x); |
|
_VirtualHand.transform.RotateAround(CalculatedRegularPoint, hand.transform.up, hand.transform.eulerAngles.y - _VirtualHand.transform.eulerAngles.y); |
|
_VirtualHand.transform.RotateAround(CalculatedRegularPoint, hand.transform.forward, hand.transform.eulerAngles.z - _VirtualHand.transform.eulerAngles.z); |
|
} |
|
else if (regular.SpecialCube) |
|
{ |
|
float Angle = 361; |
|
Quaternion TargetRotation = Quaternion.identity; |
|
Vector3 TargetPos = Vector3.zero; |
|
List<Vector3> LoopUp = new() { regular.TargetObject.right, -regular.TargetObject.up, -regular.TargetObject.right, regular.TargetObject.up }; |
|
List<Vector3> LoopForward = new() { regular.TargetObject.right, -regular.TargetObject.forward, -regular.TargetObject.right, regular.TargetObject.forward }; |
|
regular.CalculateVector3(); |
|
void UpdateAngle(Vector3 Axis) |
|
{ |
|
float _angle = Quaternion.Angle(_VirtualHand.transform.rotation, hand.transform.rotation); |
|
if (_angle < Angle) |
|
{ |
|
Angle = _angle; |
|
_VirtualHand.transform.GetPositionAndRotation(out TargetPos, out TargetRotation); |
|
} |
|
} |
|
for (int i = 0; i < 4; ++i) |
|
{ |
|
_VirtualHand.transform.RotateAround(regular.CenterPoint, transform.forward, 90); |
|
for (int j = 0; j < 4; ++j) |
|
{ |
|
_VirtualHand.transform.RotateAround(regular.CenterPoint, LoopUp[j], 90); |
|
UpdateAngle(LoopUp[j]); |
|
} |
|
} |
|
for (int i = 0; i < 4; ++i) |
|
{ |
|
_VirtualHand.transform.RotateAround(regular.CenterPoint, transform.up, 90); |
|
for (int j = 0; j < 4; ++j) |
|
{ |
|
_VirtualHand.transform.RotateAround(regular.CenterPoint, LoopForward[j], 90); |
|
UpdateAngle(LoopForward[j]); |
|
} |
|
} |
|
_VirtualHand.transform.SetPositionAndRotation(TargetPos, TargetRotation); |
|
} |
|
else |
|
{ |
|
float Angle = 361; |
|
float TargetRotation = 0f; |
|
for (int i = 1; i < 361; ++i) |
|
{ |
|
_VirtualHand.transform.RotateAround(CalculatedRegularPoint, regular.RealEnd - regular.RealStart, 1); |
|
var _angle = Quaternion.Angle(_VirtualHand.transform.rotation, hand.transform.rotation); |
|
if (_angle < Angle) |
|
{ |
|
Angle = _angle; |
|
TargetRotation = i; |
|
} |
|
} |
|
_VirtualHand.transform.RotateAround(CalculatedRegularPoint, regular.RealEnd - regular.RealStart, TargetRotation); |
|
regular.CalculateVector3(); |
|
_VirtualHand.transform.position = CalculatedRegularPoint + regular.CenterPointToHand; |
|
} |
|
RegularTransfer = false; |
|
} |
|
} |
|
if(InsideOperationPart != null && handInteraction.GetComponent<HandInteractionSetting>().OperationInsideObject) |
|
{ |
|
if (TempHand[0] == null) |
|
{ |
|
TempHand[0] = Instantiate(Hand, Hand.transform.parent); |
|
#if MIRROR |
|
var net = TempHand[0].GetComponentInChildren<HandDriverNet>(); |
|
if (net != null) net.ForbidNet(); |
|
#endif |
|
TempHand[0].name = handInteraction.name + "(Clone)"; |
|
TempHand[0].transform.SetParent(InsideOperationPart); |
|
if (hasRigid) |
|
{ |
|
Destroy(TempHand[0].GetComponent<Rigidbody>()); |
|
} |
|
TempHand[0].transform.localScale = handInteraction.transform.localScale; |
|
TempHand[0].GetComponentInChildren<HandDriver>().enabled = false; |
|
TempHand[0].GetComponentInChildren<LineRenderer>().enabled = false; |
|
|
|
Hand.GetComponent<HandInteractor>().HandVisionControl(false, TempHand[0].GetComponent<HandInteractor>()); |
|
TempHand[1] = Hand; |
|
TempHand[0].transform.SetPositionAndRotation(Hand.transform.position, Hand.transform.rotation); |
|
TempHand[0].transform.DOLocalMove(_VirtualHand.transform.localPosition, MovingOnTime); |
|
TempHand[0].transform.DOLocalRotate(_VirtualHand.transform.localEulerAngles, MovingOnTime); |
|
} |
|
return; |
|
} |
|
|
|
transform.parent = Hand.transform; |
|
bool SkipMove = Hand.transform.position == _VirtualHand.transform.position && objectFollowType != ObjectFollowType.Chasing; |
|
bool SkipRot = Hand.transform.rotation == _VirtualHand.transform.rotation; |
|
RotOffset = Quaternion.Inverse(_VirtualHand.transform.localRotation); |
|
PosOffset = _VirtualHand.transform.localPosition; |
|
|
|
CalculateGameobj.transform.parent = transform; |
|
CalculateGameobjVirtualHand.transform.parent = CalculateGameobj.transform; |
|
Transform CalculateTrans = CalculateGameobj.transform; |
|
Transform CalculateTransV = CalculateGameobjVirtualHand.transform; |
|
CalculateTrans.SetPositionAndRotation(transform.position, transform.rotation); |
|
CalculateTransV.SetPositionAndRotation(_VirtualHand.transform.position, _VirtualHand.transform.rotation); |
|
if ((CalculateTransV.localRotation != Quaternion.identity || hand.transform.rotation != Quaternion.identity)) |
|
{ |
|
if (!SkipRot) |
|
{ |
|
CalculateTrans.rotation *= RotOffset; |
|
} |
|
CalculateTransV.parent = CalculateTrans.parent; |
|
CalculateTrans.parent = CalculateTransV; |
|
|
|
PosOffset = -CalculateTrans.localPosition; |
|
} |
|
|
|
Vector3 WorldTargetPos = Hand.transform.position - _VirtualHand.transform.position + CalculateTrans.position; |
|
Quaternion WorldTargetRot = Quaternion.Inverse(_VirtualHand.transform.localRotation * Quaternion.Inverse(Hand.transform.rotation)); |
|
|
|
if ((SkipMove && SkipRot) || follow) |
|
{ |
|
if (!follow && SkipMove) |
|
{ |
|
follow = true; |
|
WhenObjInteract.Invoke(); |
|
} |
|
if (objectFollowType == ObjectFollowType.Chasing) |
|
{ |
|
transform.DOMove(WorldTargetPos, TrackingTime); |
|
transform.DORotateQuaternion(WorldTargetRot, TrackingTime); |
|
} |
|
return; |
|
} |
|
|
|
switch ((int)objectFollowType) |
|
{ |
|
case 0: |
|
transform.DOLocalMove(-PosOffset, 0); |
|
transform.DOLocalRotateQuaternion(RotOffset, 0); |
|
if(_body != null) |
|
{ |
|
Destroy(_body); |
|
Hand.GetComponent<Rigidbody>().isKinematic = Hand.GetComponent<PhysicalHand>() == null; |
|
} |
|
break; |
|
case 1: |
|
if (SlowLocalTween[0] == null) |
|
{ |
|
SlowLocalTween[0] = transform.DOLocalMove(-PosOffset, TrackingTime); |
|
SlowLocalTween[1] = transform.DOLocalRotateQuaternion(RotOffset, TrackingTime); |
|
} |
|
if (_body != null) |
|
{ |
|
Destroy(_body); |
|
Hand.GetComponent<Rigidbody>().isKinematic = Hand.GetComponent<PhysicalHand>() == null; |
|
} |
|
break; |
|
case 2: |
|
transform.DOMove(WorldTargetPos, TrackingTime); |
|
transform.DORotateQuaternion(WorldTargetRot, TrackingTime); |
|
if (_body != null) |
|
{ |
|
Destroy(_body); |
|
Hand.GetComponent<Rigidbody>().isKinematic = Hand.GetComponent<PhysicalHand>() == null; |
|
} |
|
break; |
|
case 4: |
|
if (TempHand[0] == null) |
|
{ |
|
transform.parent = null; |
|
TempHand[0] = Instantiate(Hand, handInteraction.transform.parent); |
|
TempHand[0].transform.localScale = handInteraction.transform.localScale; |
|
TempHand[0].name = handInteraction.name + "(Clone)"; |
|
TempHand[0].GetComponentInChildren<HandDriver>().enabled = false; |
|
|
|
Hand.GetComponent<HandInteractor>().HandVisionControl(false, TempHand[0].GetComponent<HandInteractor>()); |
|
TempHand[1] = Hand; |
|
TempHand[0].transform.SetPositionAndRotation(Hand.transform.position, Hand.transform.rotation); |
|
TempHand[0].transform.DOLocalMove(_VirtualHand.transform.localPosition, TrackingTime).OnComplete(() => |
|
{ |
|
SlowLocalTween[0] = transform.DOLocalMove(-PosOffset, TrackingTime).OnComplete(() => |
|
{ |
|
DestroyImmediate(TempHand[0]); |
|
DestroyImmediate(_body); |
|
TempHand[1].GetComponent<HandInteractor>().HandVisionControl(true, null); |
|
Hand.GetComponent<Rigidbody>().isKinematic = Hand.GetComponent<PhysicalHand>() == null; |
|
transform.parent = Hand.transform; |
|
}); |
|
SlowLocalTween[1] = transform.DOLocalRotateQuaternion(RotOffset, TrackingTime); |
|
}); |
|
TempHand[0].transform.DOLocalRotate(_VirtualHand.transform.localEulerAngles, TrackingTime); |
|
} |
|
break; |
|
case 5: //Distance |
|
if(TryGetComponent<SphereCollider>(out var collider)) |
|
{ |
|
collider.enabled = false; |
|
} |
|
if (SlowLocalTween[0] == null) |
|
{ |
|
|
|
SlowLocalTween[0] = transform.DOBlendableLocalMoveBy(-PosOffset - transform.localPosition, TrackingTime); |
|
DistanceCurveTween = transform.DOBlendableMoveBy(Hand.GetComponent<HandInteractor>().CurveHighestVec, TrackingTime / 2).OnComplete(() => |
|
{ |
|
DistanceCurveTween = transform.DOBlendableMoveBy(-Hand.GetComponent<HandInteractor>().CurveHighestVec, TrackingTime / 2); |
|
}); |
|
SlowLocalTween[1] = transform.DOLocalRotateQuaternion(RotOffset, TrackingTime); |
|
} |
|
if (_body != null) |
|
{ |
|
Destroy(_body); |
|
Hand.GetComponent<Rigidbody>().isKinematic = Hand.GetComponent<PhysicalHand>() == null; |
|
} |
|
break; |
|
} |
|
|
|
follow = true; |
|
WhenObjInteract.Invoke(); |
|
} |
|
|
|
public void HandDisable(Handedness handedness) |
|
{ |
|
if (transform.parent != null && transform.parent.GetComponent<HandInteractor>() != null && (int)transform.parent.GetComponent<HandInteractor>().handness == (int)handedness) |
|
{ |
|
if(objectFollowType != ObjectFollowType.Distance) |
|
{ |
|
SlowLocalTween[0].Complete(); |
|
SlowLocalTween[1].Complete(); |
|
} |
|
else |
|
{ |
|
if (TryGetComponent<SphereCollider>(out var collider)) |
|
{ |
|
collider.enabled = true; |
|
} |
|
SlowLocalTween[0].Kill(); |
|
SlowLocalTween[1].Kill(); |
|
DistanceCurveTween.Kill(); |
|
} |
|
SlowLocalTween[0] = null; |
|
BackReset = objectFollowType == ObjectFollowType.SlowMove; |
|
transform.parent = null; |
|
RegularTransfer = true; |
|
} |
|
if(Hand != null) |
|
{ |
|
var handRigid = Hand.GetComponent<Rigidbody>(); |
|
handRigid.isKinematic = false; |
|
if (hasRigid && !gameObject.TryGetComponent<Rigidbody>(out _)) |
|
{ |
|
_body = gameObject.AddComponent<Rigidbody>(); |
|
_body.velocity = handRigid.mass / _body.mass * handRigid.velocity; |
|
_body.angularVelocity = handRigid.mass / _body.mass * handRigid.angularVelocity; |
|
hasRigid = true; |
|
onThrow = true; |
|
if(InsideOperationPart == null) |
|
{ |
|
TempHand = new GameObject[2] { null, null }; |
|
} |
|
} |
|
} |
|
if (TempHand[0] != null && !TempHand[0].name.Contains("Release")) |
|
{ |
|
TempHand[0].name += "(Release)"; |
|
TempHand[0].transform.DOMove(TempHand[1].transform.position, MovingOnTime); |
|
TempHand[0].transform.DORotateQuaternion(TempHand[1].transform.rotation, MovingOnTime); |
|
Invoke(nameof(HandBack), MovingOnTime); |
|
} |
|
Hand = null; |
|
follow = false; |
|
WhenObjDisable.Invoke(); |
|
} |
|
|
|
private void HandBack() |
|
{ |
|
Destroy(TempHand[0]); |
|
TempHand[1].GetComponent<HandInteractor>().HandVisionControl(true, null); |
|
TempHand = new GameObject[2] { null, null }; |
|
} |
|
|
|
private bool ActiveLock; |
|
public void SetActiveLock(bool value) |
|
{ |
|
ActiveLock = value; |
|
} |
|
|
|
public Transform GetReferenceHand(int index) |
|
{ |
|
return TempHand[index]?.transform; |
|
} |
|
|
|
public void AutoCheckHand() |
|
{ |
|
var interactions = GetComponentsInChildren<HandInteraction>().ToList(); |
|
for(int i = interactions.Count - 1; i >= 0; i--) |
|
{ |
|
if (interactions[i].transform.TryGetComponent(out FingerUseInteraction UseInteract)) |
|
{ |
|
interactions.Remove(UseInteract.PreposeInteraction); |
|
} |
|
} |
|
AllInteractions = interactions.ToArray(); |
|
if (!Application.isPlaying) |
|
{ |
|
HandInteractions = interactions.ToArray(); |
|
} |
|
} |
|
|
|
public void SwitchHandInteractioinPlan(int index) |
|
{ |
|
if (!enableInteractionPlans || index < 0 || index >= InteractionPlan.Length) |
|
{ |
|
return; |
|
} |
|
|
|
HandInteractions = InteractionPlan[index].handInteractions; |
|
} |
|
|
|
public void SwitchHandInteractioinPlan(string name) |
|
{ |
|
if (!enableInteractionPlans || string.IsNullOrEmpty(name)) |
|
{ |
|
return; |
|
} |
|
|
|
foreach (var items in InteractionPlan) |
|
{ |
|
if (items.Name == name) |
|
{ |
|
HandInteractions = items.handInteractions; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
} |
|
}
|
|
|