110 lines
3.6 KiB
C#
110 lines
3.6 KiB
C#
using UnityEngine;
|
||
using UnityEngine.XR.Interaction.Toolkit;
|
||
using System.Collections;
|
||
|
||
namespace LevelUp.GrabInteractions
|
||
{
|
||
public class ResetObjectSmooth : ResetObject
|
||
{
|
||
[Header("平滑重置设置")]
|
||
[SerializeField] private float resetSpeed = 5f;
|
||
[SerializeField] private float stopDistance = 0.01f;
|
||
|
||
private Quaternion returnToRotation;
|
||
private Rigidbody rb;
|
||
private Coroutine smoothMoveCoroutine;
|
||
private bool initialIsKinematic;
|
||
// 新增:用于备份物理插值设置
|
||
private RigidbodyInterpolation initialInterpolation;
|
||
|
||
protected new void Awake()
|
||
{
|
||
base.Awake();
|
||
rb = GetComponent<Rigidbody>();
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
base.Start();
|
||
returnToRotation = transform.rotation;
|
||
|
||
if (rb != null)
|
||
{
|
||
initialIsKinematic = rb.isKinematic;
|
||
initialInterpolation = rb.interpolation; // 记录初始插值状态
|
||
}
|
||
}
|
||
|
||
void OnDestroy() => StopAllCoroutinesAndCancelInvoke();
|
||
|
||
private void StopAllCoroutinesAndCancelInvoke()
|
||
{
|
||
CancelInvoke(nameof(ReturnHome));
|
||
if (smoothMoveCoroutine != null)
|
||
{
|
||
StopCoroutine(smoothMoveCoroutine);
|
||
smoothMoveCoroutine = null;
|
||
}
|
||
}
|
||
|
||
protected override void OnSelect(SelectEnterEventArgs arg0) => StopAllCoroutinesAndCancelInvoke();
|
||
|
||
protected override void OnSelectExit(SelectExitEventArgs arg0)
|
||
{
|
||
StopAllCoroutinesAndCancelInvoke();
|
||
if (rb != null)
|
||
{
|
||
rb.isKinematic = false;
|
||
rb.WakeUp();
|
||
}
|
||
base.OnSelectExit(arg0);
|
||
}
|
||
|
||
protected override void ReturnHome()
|
||
{
|
||
if (shouldReturnHome)
|
||
smoothMoveCoroutine = StartCoroutine(SmoothMoveToHome());
|
||
}
|
||
|
||
private IEnumerator SmoothMoveToHome()
|
||
{
|
||
if (rb != null)
|
||
{
|
||
// 【关键优化 1】禁用物理插值,防止物理引擎尝试预测物体的 Transform 更新
|
||
rb.interpolation = RigidbodyInterpolation.None;
|
||
rb.isKinematic = true;
|
||
rb.velocity = Vector3.zero;
|
||
rb.angularVelocity = Vector3.zero;
|
||
}
|
||
|
||
float stopDistanceSqr = stopDistance * stopDistance;
|
||
|
||
while ((transform.position - returnToPosition).sqrMagnitude > stopDistanceSqr)
|
||
{
|
||
float lerpFactor = 1f - Mathf.Exp(-resetSpeed * Time.deltaTime);
|
||
|
||
transform.position = Vector3.Lerp(transform.position, returnToPosition, lerpFactor);
|
||
transform.rotation = Quaternion.Slerp(transform.rotation, returnToRotation, lerpFactor);
|
||
|
||
yield return null;
|
||
}
|
||
|
||
transform.position = returnToPosition;
|
||
transform.rotation = returnToRotation;
|
||
|
||
// 【关键优化 2】在恢复物理属性前,等待一个物理帧,确保位置同步完成
|
||
yield return new WaitForFixedUpdate();
|
||
|
||
if (rb != null)
|
||
{
|
||
rb.isKinematic = initialIsKinematic;
|
||
// 【关键优化 3】恢复初始插值设置
|
||
rb.interpolation = initialInterpolation;
|
||
rb.velocity = Vector3.zero;
|
||
rb.angularVelocity = Vector3.zero;
|
||
}
|
||
|
||
smoothMoveCoroutine = null;
|
||
}
|
||
}
|
||
} |