Unity Udexreal开发插件包
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

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;
}
}
}
}
}